spring声明式事务(@Transactional)开发常犯的几个错误及解决办法.docx
第
spring声明式事务(@Transactional)开发常犯的几个错误及解决办法
问题现象:在事务提交后回调事件方法中【即:afterCommit】开启事务不生效(即:添加了@Transactional,也执行了代理方法的调用,但就像没有事务一样,出现报错事务不回滚,也无法在事务方法中再次注册事务提交后回调事务件方法),示例代码如下:
/**代码片段
*@authorzuowenjun
*@see
@Transactional
publicDemoUserdoGetX(){
doInsert(1);
TransactionSynchronizationManager.registerSynchronization(newTransactionSynchronizationAdapter(){
@Override
publicvoidafterCommit(){
selfService.doInsert(2);//走切面调用,确保执行代理的事务方法,但实际还是无事务,报错也不会回滚
returndemoUserMapper.get(1);
@Transactional(propagation=Propagation.REQUIRED)
publicintdoInsert(intid){
DemoUseruser=newDemoUser(id,zs,18,newBigDecimal(8888.88),
shenzhen,cn,newTimestamp(System.currentTimeMillis()),newTimestamp(System.currentTimeMillis()));
intresult=demoUserMapper.insert(user);
if(id==2){
thrownewRuntimeException(mockinsertex
returnresult;
//演示调用:虽然doGetX有报错,但最终doInsert方法均有执行,且都能查出ID=1与2的记录
try{
DemoUserresult=demoUserService.doGetX();
System.out.println(result!=nullresult.toString():none
}catch(Exceptione){
System.out.println(error+e.toString());
DemoUserresult1=demoUserService.get(1);
System.out.println(result1!=nullresult1.toString():none
DemoUserresult2=demoUserService.get(2);
System.out.println(result2!=nullresult2.toString():none
根本原因:在事务提交后回调事件方法中【即:afterCommit】,spring事务的管理状态仍保留(即:仍是事务激活状态)但DB事务其实已提交,当回调方法中又遇到有事务注解的方法时且判断已有事务(即spring事务的管理状态是激活状态transactionActive=true)时,若是默认继承状态则不会再开启新事务,仅复用DB连接
解决方案:在事务提交后回调事件方法中【即:afterCommit】开启新事务(即:传播特性为:REQUIRES_NEW)或者执行前强制清除事务状态【需要编写事务状态清除工具类】,示例代码如下:
/**代码片段
*@authorzuowenjun
*@see
@Transactional
publicDemoUserdoGetX(){
TxManagerUtils.clearTxStatus();//方案二:通过事务状态清除工具类注册事务回调后首先清除事务状态,二选其一即可
doInsert(1);
TransactionSynchronizationManager.registerSynchronization(newTransactionSynchronizationAdapter(){
@Override
publicvoidafterCommit(){