所谓声明式事务,也就是通过配置的方式,比如通过配置文件xml或者注解的方式,来告诉Spring哪些方法需要Spring帮忙管理事务,然后开发者只需要关注业务代码,而事务的事情则由Spring自动帮我们控制。
配置文件的方式:即在spring.xml文件中进行统一配置,开发者基本不用关注事务的事情了,一切交给spring处理。
基于注解的方式:只需要在想要添加事务的方法上加上@Transaction注解就可以了。
实际工作中,基于配置文件的方式用的很少,我们工作中主要还是用注解的方式较多。
简单介绍一下原理:
当spring容器启动的时候,发现有@EnableTransactionManagement注解,此时会拦截所有bean的创建,然后会扫描一下bean上是否有@Transaction注解(类、接口、或者方法上有这个注解都可以),如果有这个注解,spring会通过aop的方式给这个bean生成代理对象(代理对象中存在本类对象),代理对象中会增加一个拦截器,拦截器会拦截bean中public方法的执行,会在方法执行前启动事务,方法执行完毕之后提交或者回滚事务。
其实仔细看了上面的原理,也就很好解释了为什么会失效了。
首先,外部调用A方法时,是通过代理对象来调用的,如ProxyService.A(),而我们在A方法中调用B方法是通过本类对象Service来实现的,即Service.B(),因为代理对象中存在Service对象。所以这就会导致事务失效。
必须通过代理对象来调用方法,事务才会生效。
注意代理对象最终都是要调用原始对象的,而原始对象去调用方法时,是不会再触发代理了。
1、如果A加了@Transaction注解,B上有没有@Transaction注解,事务都是有效的,则AB在同一个事务中。
2、如果A不加@Transaction注解,B上有没有@Transaction注解,事务都是无效的。
1、如果A加了@Transaction注解,B上有没有@Transaction注解,事务都是有效的。
2、如果A不加@Transaction注解,B加了@Transaction注解,只有B是有事务的。
3、如果A不加@Transaction注解,B也不加@Transaction注解,A和B都是没有事务的。
简单理解:
只要A加了@Transaction注解,那么无论是不是在同一个类中,无论B加不加注解,AB都在同一个事务中。
A不加注解,B加了注解,如果AB在同一个类中,则事务失效;如果AB不同类,则只有B有事务。
原因分析:在A方法有@Transaction注解时,spring在管理的时候会生成一个代理类,在外部调用A方法时,实际执行的是代理类里面的方法,该代理类里面的方法已经包括了B方法的调用,已经成为了一个方法,所以事务是有效的。
1、方法不是public类型的
@Transaction注解可以用在类、接口和方法上,如果将@Transaction注解用在了非public方法上,事务将失效。
2、向上述所说的方法调用场景
3、异常类型错误
spring事务的回滚机制:对业务方法进行try-catch,如果捕获到有指定的异常时,spring会自动对事务进行回滚。
那么问题来了,哪些异常会让spring自动回滚事务呢?并不是任何异常情况下,spring都会回滚事务的,默认情况下,RuntimeException和Error异常情况下,spring才会回滚事务。当然也可以自定义回滚的异常类型。