Spring提供了很简单、很便捷的事务管理方式,通过Transaction注解,即可实现事务处理。
但是在使用中,也需要注意一些关键点。
1、必须是spring proxy的对象,才会触发事务(@Transaction注解才会生效)。
比如:Class A,里面有方法 method1和method2,两个方法均注解了@Transaction
@Transactional(propagation = Propagation.NEVER)
public void getDeps(long ID) {
System.out.println(databaseImp.getDepartmentByID(ID));
}
@Transactional(propagation = Propagation.REQUIRED)
public void allProcessOnDB_second(long ID) {
getDeps(ID);
operation(ID);
}
@Transactional
public void operation(long id){
System.out.println(databaseImp.getDepartmentByID(id));
}
上面这段代码,在同一个class中,会发现即使设置了Propagation.NEVER,也不会抛出异常。
因为在同一个class内部的方法之间的调用,并没有经过spring proxy,所以不会触发事务。
(可以理解为,同一个class内部,方法之间的调用,在经过代码编译后,所有代码都是在同一个代码块中执行的,并不需要经过spring proxy,故也不会触发@Transaction注解的事务管理)
如果将getDeps方法放在另一个class中,在allProcess方法中调用xxx.getDeps方法,此时就会抛出异常。
2、Transaction事务的传递机制
默认情况,我们都是直接使用@Transactional注解,即可使用事务。但是当出现一些特殊情况时,就不能简单这么使用了。
比如,有些情况,我们需要在method1调用method2的情况下,method2作为单独的事务提交,method1出现异常回滚,不影响method2的提交。
此时,就需要用到PROPAGATION_REQUIRES_NEW模式。
Spring事务具体的模式有7类,具体的可以参考下面的文章。
做了一些小实验,结果如下:(NEST模式,开发环境不支持,暂时没实验)
场景:Class A里面的方法method1,调用Class B里面的方法method2
-
method1 是默认Transaction,method2 是默认的Transaction
任意方法抛出异常,则回滚(两个方法在同一个事务下)
-
method1是默认Transation,method2是PROPAGATION_NEVER
运行异常,因为method2不能以事务运行,但是检测到在method1的事务下了。
-
method1是默认Transaction, method2是PROPAGATION_NOT_SUPPORT
method1发生异常,method2不影响,提交成功,method1回滚
method2发生异常,method2不影响,提交成功,method1回滚
-
method1是默认,method2是PROPAGATION_REQUIRES_NEW
method1发生异常,method2提交,method1回滚
method2发生异常,method2回滚,如果method1没有try catch,则回滚,否则提交
注意:对于使用PROPAGATION_REQUIRES_NEW的情况下,method2是无法获取method1中还未提交的数据的,因为两者是相互独立的事务。
对于使用PROPAGATION_NOT_SUPPORT的情况,也是无法获取未提交的数据的,因为method2不在method1的事务里。