Spring事务失效的各种场景( 二 )

六、设计的表不支持事务我们都知道,MySQL5之前默认的数据库引擎是MyISAM,可能一些老的项目还在使用,但是他是不支持事务的
七、没有开启事务如果创建的不是springboot项目可能会导致这样的问题出现,因为springboot项目有自动装配的类
DataSourceTransactionManagerAutoConfiguration,已经默认开启了事务,配置spring.datasource参数就行,如果是spring项目,需要在ApplicationContext.xml配置的,不然事务不会生效
<!-- 配置事务管理器 --> <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager"><property name="dataSource" ref="dataSource"></property> </bean> <tx:advice id="advice" transaction-manager="transactionManager"><tx:attributes><tx:method name="*" propagation="REQUIRED"/></tx:attributes> </tx:advice> <!-- 用切点把事务切进去 --> <aop:config><aop:pointcut expression="execution(* com.demo.*.*(..))" id="pointcut"/><aop:advisor advice-ref="advice" pointcut-ref="pointcut"/> </aop:config> 还有就是切点配错,也会导致事务失效
八、错误的事务传播我们在使用@Transactional注解时,是可以指定propagation参数的 。
该参数的作用是指定事务的传播特性,
spring目前支持7种传播特性:
• REQUIRED 如果当前上下文中存在事务,那么加入该事务,如果不存在事务,创建一个事务,这是默认的传播属性值 。
• SUPPORTS 如果当前上下文存在事务,则支持事务加入事务,如果不存在事务,则使用非事务的方式执行 。
• MANDATORY 如果当前上下文中存在事务,否则抛出异常 。
• REQUIRES_NEW 每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行 。
• NOT_SUPPORTED 如果当前上下文中存在事务,则挂起当前事务,然后新的方法在没有事务的环境中执行 。
• NEVER 如果当前上下文中存在事务,则抛出异常,否则在无事务环境上执行代码 。
• NESTED 如果当前上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务 。
如果我们在手动设置propagation参数的时候,把传播特性设置错了
@Servicepublic class DemoService {@Transactional(propagation = Propagation.NEVER)publicvoid query(Demo demo) {}}我们可以看到query的事务传播设置为了Propagation.NEVER,这种类型的传播不支持事务,会抛异常,
目前支持事务的三种传播特性为:REQUIRED,REQUIRES_NEW,NESTED
九、自己捕获了异常事务不回滚,可能是我们在写代码的时候自己在代码手动进行了try…catch
@Transactionalpublicvoid query(Demo demo) {try {save(demo);} catch (Exception e) {System.out.println("异常");}}这种情况下,spring事务不会进行回滚,因为我们进行了手动捕获异常,然后没有手动抛出,如果想要spring事务的正常回滚,必须抛出它能处理的异常,如果没有抛出异常,spring会认为程序没有问题 。
十、手动抛出别的异常我们没有手动捕获异常,但是如果抛出的异常不正确,spring事务也不会回滚 。
@Transactionalpublicvoid query(Demo demo) throws Exception{try {save(demo);} catch (Exception e) {throw new Exception(e);}}上面我们捕获了异常,然后手动抛出Exception,事务同样不会回滚,因为spring事务,默认情况下不会回滚Exception(非运行时的异常),只会回滚RuntimeException(运行时异常)和Error(错误) 。
十一、自定义回滚异常在使用@Transactional注解声明事务时,有时我们想自定义回滚的异常,spring也是支持的 。可以通过设置rollbackFor参数,来完成这个功能 。
但如果这个参数的值设置错了,就会引出一些问题
@Transactional(rollbackFor = BusinessException.class)publicvoid query(Demo demo) throws Exception{save(demo);}上面是我们自定义的业务异常,如果在执行上面这段代码,保存和更新数据时,程序报错了,抛了SqlException、DuplicateKeyException等异常 。而BusinessException是我们自定义的异常,报错的异常不属于BusinessException,所以事务也不会回滚 。即使rollbackFor有默认值,但阿里巴巴开发者规范中,还是要求开发者重新指定该参数 。
因为如果使用默认值,一旦程序抛出了Exception,事务不会回滚,这会出现很大的bug 。所以,建议一般情况下,将该参数设置成:Exception或Throwable 。


推荐阅读