Spring事务常见问题和解决办法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_15003505/article/details/81032222

Spring事务配置主要有两种,第一种是XML配置方法前缀,第二种方法是使用注解。很多项目中或多或少都使用过这两种方式,但是我这里推荐优先使用注解的方式。为什么?下面总结说。

列出我在开发、测试中遇到的几个问题(使用XML和开启事务注解)。

<!-- XML配置事务的传播特性 -->
    <tx:advice id="txAdvice">
        <tx:attributes>
            <!--以save、delete、update字母开的的方法设置事务 -->
            <tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="del*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="bulk*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="check*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="reject*" propagation="REQUIRED" rollback-for="Exception" />
            <!--其他方法事务只读,提高性能 -->
            <tx:method name="*" propagation="REQUIRED" read-only="true" />
        </tx:attributes>
    </tx:advice>
<!-- 配置事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

1. Connection is read-only

java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:998)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:937)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:872)
	at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1139)

这个错误是因为XML中已经配置了其他方法(即不是那些单词开头的)都是只读的,当你去做增删改的时候就会报错。

解决办法:

1、遵循XML配置的方法前缀。

2、使用@Transactional注解修饰,名称无所谓。

2. UnexpectedRollbackException

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:720)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:521)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)

这个问题估计在事务方法中出现的频次很高,但是很多人都不清楚为什么出现。原因是因为当前事务方法中去调用其他事务方法(事务的传播性),结果被调用的方法出现异常了,而这个异常又在当前方法中捕获了该异常且没有做处理:

try {
  buss.addOrder(order);
} catch (Exception e) {
  e.printStackTrace();
  //开启事务时不应该捕获异常或者应该抛出
}

解决办法:

1、既然开启了事务就应该让事务回滚,而不是捕获异常(事实上,当使用XML配置事务的时候,是被强迫使用了事务,结果因为没有处理好导致这种错误)!

2、或者把异常抛出,让事务正常回滚(不过这样做的话,下面的方法都不会执行了,既然这样那你开启事务是为了什么?)。

3、被调用的方法再开启一个新的事务,而不是使用当前事务。不过这样做的话需要配合注解来做了——@Transactional(propagation = Propagation.REQUIRES_NEW),但由于XML和注解存在优先级问题不一定生效(取决于顺序配置),同时需要对出现异常的方法进行上面类似的catch。但这么做,无非就是让事务不回滚,那你开启事务的意义何在?

归根结底:正确的解决办法就是既然开启事务就应该让事务去管理,而不是catch!。

3. XML与注解哪个优先级高?

都高,取决于你配置的顺序。即谁放在最下面谁的优先级就高。这个问题,我也搜了一些资料,各有各的说法,有说注解高的也有说XML高的,但最后我在测试过程得出这样的结论。

4. 那么,我们使用哪种配置最好呢?

我在这里还是推荐使用注解的方式,原因两点:

1、使用XML的方式有局限性、不灵活,很多时候我们的方法并不需要事务,还有些方法我的命名也不一定是这样的。强制使用事务并不是一个好的做法,使用不当反而会造成其他的问题,特别是对事务理解不透的开发者很难处理好事务问题。

2、微服务、Spring Boot出来后,配置就少了很多,基本上都是基于注解开发,我们没必要把时间都浪费在配置上面。

支持我写更多的优质文章,支付宝扫一扫:

猜你喜欢

转载自blog.csdn.net/qq_15003505/article/details/81032222