事务异常手动回滚且方法正常返回
背景
小X调事务接口A,接口通过@Transactional进行注解,接口A中调用数据库操作接口B
接口A对接口B调用操作进行try-catch-finally
接口B中有异常产生,会导致接口返回事务异常错误形式,影响外系统使用。
接口B异常需要回滚,但是为了外系统使用,接口A需要正常返回
解决方案
1.catch代码块中使用手动回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();这样就无须接口A上的事务进行处理异常
DEMO验证列表
- 测试只读事务只允许读取数据,不允许语句修改和插入
- 测试RuntimeException 回滚事务与否
- 测试RuntimeException 手动回滚事务+正常返回
- 测试非RuntimeException 回滚事务与否
- 测试非RuntimeException catch异常,正常返回,不回滚事务
- 测试非RuntimeException throw RuntimeException异常,回滚事务
- 测试同一个类中 非事务方法调用事务方法
- 测试不同类中 非事务方法调用事务方法
- 测试不同类中 事务方法嵌套调用事务方法,requirednew 嵌套事务异常 外层事务同时会回滚
- 测试不同类中 事务方法嵌套调用事务方法,requirednew 外层事务异常 外层事务同时会回滚,嵌套事务不会回滚
扩展
只读事务和非只读事务的区别
只读事务:1.一个接口中如果执行多条报表查询,为了确保数据一致性,是需要给该接口增加只读事务的; 2.只读事务中不能进行语句的插入或者修改操作 3.只读事务异常,不会进行事务回滚
非只读事务:1.能进行语句修改和插入;2.会进行事务回滚
同一个类中非事务方法调用事务方法,因为类会产生代理类,代理类调用target类的非事务方法,导致实际调用执行为target中的事务方法(没有进行AOP代理)
spring xml事务配置
<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- 首先我们要把服务对象fooService声明成一个bean -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- 然后是声明一个事物建议tx:advice,spring为我们提供了事物的封装,这个就是封装在了<tx:advice/>中 -->
<!-- <tx:advice/>有一个transaction-manager属性,我们可以用它来指定我们的事物由谁来管理。 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- 配置这个事务建议的属性 -->
<tx:attributes>
<!-- 指定所有get开头的方法执行在只读事务上下文中 -->
<tx:method name="get*" read-only="true"/>
<!-- 其余方法执行在默认的读写上下文中 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 我们定义一个切面,它匹配FooService接口定义的所有操作 -->
<aop:config>
<!-- <aop:pointcut/>元素定义AspectJ的切面表示法,这里是表示x.y.service.FooService包下的任意方法。 -->
<aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
<!-- 然后我们用一个通知器:<aop:advisor/>把这个切面和tx:advice绑定在一起,表示当这个切面:fooServiceOperation执行时tx:advice定义的通知逻辑将被执行 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>
<!-- 数据元信息 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>
<!-- 管理事务的类-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- other <bean/> definitions here -->
</beans>
引用
RuntimeException和Exception的区别 https://www.cnblogs.com/jtlgb/p/5985120.html
https://zhuanlan.zhihu.com/p/38208248
https://zhuanlan.zhihu.com/p/56070261