事务指的就是一个操作单元,在这个操作单元中的所有操作最终要保持一致的行为,要么同时成功,要么同时被撤销。
本地事务其实可以认为是数据库提供的事务机制。说到数据库事务就不得不说,数据库事务中的四大特性:
在单体应用中,一个转账操作,A向B转账100块,A扣100块,B增加100块,那么这两个操作是强关联,要么同时成功,要么同时失败。否则就会出现A减少了100块,而B没有变化。
下面的例子,用两个insert操作来进行演示,正常情况下,两个insert都能成功。
@Override
public void insertTest(String name1,String name2) {
{
//第一个操作
User user = new User();
user.setName(name1);
userMapper.insert(user);
log.info("插入数据" + JSON.toJSONString(user));
}
{
//第二个操作
User user = new User();
user.setName(name2);
userMapper.insert(user);
log.info("插入数据" + JSON.toJSONString(user));
}
}
测试以下demo,调用插入操作,数据库可以看到增加了两条数据。


从数据库查看,可以知道name长度为varchar(10),我们测试的时候,可以让name2长度超过10,此时就会发生第二个insert失败的情况,而第一个insert则成功。

我们直接让name1长度小于10位,name2长度大于10位,此时发生了异常,查看数据库,发现第一个insert的记录在数据库中可以看到,第二个insert则没有插入到数据库,这就发生了事务问题。


针对上面演示的问题,明显我们希望是两个insert同时成功或者失败,怎么解决呢?我们可以使用@Transactional注解添加在方法头上
import org.springframework.transaction.annotation.Transactional;
.......
.......
@Transactional //开启事务
public void insertTest(String name1,String name2) {
//数据库操作1
//数据库操作2
...
}

使用注解后,再次测试,同样发生了内容长度超长的问题,查看数据库,发现数据库并没有新增记录,很显然第2个insert的失败和第1个insert的成功是同一个事务,所以虽然第一个insert成功,但是第二个操作失败了,所以数据被回滚了,保证了事务的完整性,同时成功或失败。


再次发一个成功的操作,查看日志插入成功,观察数据库,发现id没有25这条记录,很显然id为25这条记录实际插入过了,只不过被rollback了。这也印证了使用@Transactional可以保证本地事务,替代了原来的自己保存savepoint,再rollback的复杂操作。

