我是靠谱客的博主 高贵百褶裙,最近开发中收集的这篇文章主要介绍Spring事务异常UnexpectedRollbackException出现原因以及解决方法,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

异常信息:

org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only

	at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:533)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
	

问题还原:

@Repository
public interface ConsumeTaskLockRepository extends CrudRepository<ConsumeTaskLock, Long> {

   // 省略代码
}

service方法:

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
    public boolean getLock(String ip, String owner) {
        int insertCnt = 0;
        try {
        	// 当插入记录主键存储重复时,consumeTaskLockRepository.insert方法调用失败,会由Hibernate事务事务管理器标记为回滚
            insertCnt = consumeTaskLockRepository.insert(ip, new Date(), owner);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.warn("ip = {} owner = {} get lock failed!", ip, owner);
            // 此处我们吞没了异常以为了事务是可以提交的,但是由于insert主键冲突Hibernate事务事务管理器标记为回滚,因此在Spring真正进行事务提交检查时候会失败
            // 抛出异常:org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only
        }
        return insertCnt > 0;
    }

解决办法:

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
    public boolean getLock(String ip, String owner) {
        int insertCnt = 0;
        try {
            insertCnt = consumeTaskLockRepository.insert(ip, new Date(), owner);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.warn("ip = {} owner = {} get lock failed!", ip, owner);
            // 手动标记事务回滚,此处标记回滚;该方法执行完毕不会执行提交操作,直接回滚因此不会有如上异常
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return insertCnt > 0;
    }

这个问题一般性产生原因:

      事务调用链路(事务传播性:org.springframework.transaction.TransactionDefinition#PROPAGATION_REQUIRED):A->B->C 时,在C中调用出现异常之后,该异常被Spring事务管理器捕获之后标记事务回滚;C执行返回A时,A对B->C的调用异常进行了try-catch之后吞没了异常而没有再次抛出,因此A方法结束之后Spring事务管理器认为事务是可以提交的,但是在C方法已经标记失败,因此冲突抛出异常。

 

注意:Spring事务管理时候一定要切记异常如何处理,是否再次抛出!!!大道理都懂,时长疏忽犯错。

 

最后

以上就是高贵百褶裙为你收集整理的Spring事务异常UnexpectedRollbackException出现原因以及解决方法的全部内容,希望文章能够帮你解决Spring事务异常UnexpectedRollbackException出现原因以及解决方法所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部