转载自:https://www.jianshu.com/p/ec899855f049
叙述
对于 Java 后端开发人员,Spring 事务注解几乎天天都会接触。但是,你真的全部了解 Spring 事务注解的细节吗?今天我们就来深入讨论一下 Spring 事务注解中回滚、传播行为和只读这三个属性的配置调优。
希望通过本文能让大家了解更多和数据库事务相关的框架,以及数据库引擎的内部原理,为大家的数据库优化工作提供一些有用的建议。
为什么要配置 rollbackFor = Exception.class
最近,阿里将其编码规范按照 IDE 插件的方式发布。插件检查结果中有这么一条:“Spring 事务需要设置 rollbackFor 属性或者显式调用 rollback 方法”。为什么需要设置 rollbackFor 属性呢?
简单来说,如果不设置 rollbackFor = Exception.class
,则当方法抛出检查型异常时,数据库操作不会回滚。
举例来说,对于下面的代码:
@Transactional
public void demo() throws Exception {
this.userRepository.save(new User(USERNAME));
throw new Exception("No Rollback");
}
执行完毕之后,数据库中会增加一条 user 记录。如果你希望在方法抛出检查型异常后触发数据库回滚,那你需要这样写:
@Transactional(rollbackFor = Exception.class)
public void demo() throws Exception {
this.userRepository.save(new User(USERNAME));
throw new Exception("No Rollback");
}
或者使用 TransactionStatus.setRollbackOnly()
手动触发回滚:
@Transactional
public void demo() {
this.userRepository.save(new User(USERNAME));
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
如果你的方法没有声明异常,只会抛出运行时异常,则不需要设置 rollbackFor。运行时异常抛出后会触发事务回滚。
@Transactional
public void demo() {
this.userRepository.save(new User(USERNAME));
throw new RuntimeException("Rollback");
}
如果代码如上所示,则不会有新的 user 记录。因为数据库操作回滚了。
需不需要配置 rollbackFor
因为如果方法会抛出检查型异常,则必须在方法中声明异常。因此,一般而言,如果方法没有声明异常,则不需要配置在 Spring 事务注解中配置 rollbackFor。
另外,我在阿里的 Java 编码规范里也没有找到关于设置 rollbackFor 的内容。因此,我的个人意见是方法不抛出检查型异常就不必设置 rollbackFor。
Spring 为何这么设计
对于 Spring 为什么默认不回滚检查型异常这个问题,我想是和 Java 异常处理的原则有关。原则上,检查型异常都是业务异常流的一部分,需要开发人员定制开发相应的异常处理功能。既然需要开发人员定制,自然 Spring 认为自己不必画蛇添足了,自动地回滚数据库操作。