Spring Boot事务配置管理
事务相关
事务的作用就是为保证用户的每一个操作都是可靠的,事务中的每一步操作都必须成功执行,只要有发生异常就回退到事务开始未进行操作的状态。这很好理解,转账、购票等等,必须整个事件流程全部执行完才能人为该事件执行成功,不能转钱转到一半,系统死了,转账人钱没了,收款人钱还没到。
Spring Boot事务配置
-
依赖导入
导入依赖之后会自动注入
DataSourceTransactionManager
无需其他配置就可使用@Transactional
注解进行事务的使用l。 -
简单测试(略)
-
常见问题:
-
异常未被捕获到的情况
示例代码:
@Service public class UserServiceImpl implements UserService { @Resource private UserMapper userMapper; @Override @Transactional public void isertUser2(User user) throws Exception { // 插入用户信息 userMapper.insertUser(user); // 手动抛出异常 throw new SQLException("数据库异常"); } }
上面这个代码,其实并没有什么问题,手动抛出一个
SQLException
来模拟实际中操作数据库
发生的异常,在这个方法中,既然抛出了异常,那么事务应该回滚,实际却不如此。因为 Spring Boot 默认的事务规则是遇到运行异常(
RuntimeException
)和程序
错误(Error
)才会回滚。比如上面我们的例子中抛出的RuntimeException
就没有问题,但是抛出SQLException
就无法回滚了。针对非运行时异常,如果要进行事务回滚的话,可以在
@Transactional 注解中使用rollbackFor
属性来指定异常,比如@Transactional(rollbackFor = Exception.class)
,这样就没有问题了,所以在实际项目中,一定要指定异常。 -
异常被 ”吃“ 掉的情况
在处理异常时,有两种方式,要么抛出去,让上一层来捕获处理;要么把异常 try catch 掉,在异常出现的地方给处理掉。就因为有这种 try...catch,所以导致异常被 ”吃“ 掉,事务无法回滚。
解决办法:直接往上抛,给上一层来处理即可,千万不要在事务中把异常自己 ”吃“ 掉
-
事务的范围
并发场景下,方法上加了
@Transactional
,方法内部使用synchronized
关键字,该方法执行,事务启动,整个方法执行结束,事务关闭。出现问题的原因是:因为事务的作用范围比锁的范围大,也就是说,在加锁的那部分代码执行完之后,锁释放掉了,但是事务还没结束,此时另一个线程进来了,事务没结束的话,第二个线程进来时,数据库的状态和第一个线程刚进来是一样的。即由于mysql Innodb
引擎的默认隔离级别是可重复读(在同一个事务里,SELECT的结果是事务开始时时间点的状态),线程二事务开始的时候,线程一还没提交完成,导致读取的数据还没更新。第二个线程也做了插入动作,导致了脏数据。
-