美文网首页
Spring 事务传播行为和隔离级别的应用

Spring 事务传播行为和隔离级别的应用

作者: Jason__Ding | 来源:发表于2018-07-13 15:21 被阅读53次

    一言蔽之

    对Spring事务了解一直处于理论阶段,几个事务传播行为(propagation behaviors),几个隔离级别(isolation levels)看了又忘,忘了又看。近期的开发中遇到了几个有趣的例子,拿出来晒晒。

    具体应用

    1. 在catch块中,继续进行数据库操作

    场景

    以下是简化后的Kotlin代码
    execute()在事务内执行
    doSomeThing()可能会抛出RuntimeException
    fail() 会对数据库有一些修改操作

    
    @Transactional
    override fun execute() {
        try {
            doSomeThing()
        } catch (e: Exception) {
            fail()
        }
    }
    
    override fun fail() {
       saveLogToDB()
    }
    

    问题
    如果doSomeThing()抛出RuntimeException,fail()在执行数据库操作时,会抛出异常:
    org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

    分析&思路

    1. 方法saveLogToDB()执行时事务已经被标记为rollback-only
    2. saveLogToDB()使用的事务是在execute()方法执行之前创建的
    3. doSomeThing()执行的某个步骤中,因为触发异常,事务被标记为rollback-only
    4. 那么,为了saveLogToDB()能够保存数据到数据库,就不能够使用execute()方法的事务了。

    回忆以下有哪些事务的传播行为:

    // 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
        // @Transactional 注解默认采用这个方案
        REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
    
        // 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
        SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
    
        // 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
        MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
    
         // 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
        REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
    
        // 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
        NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
    
        // 以非事务方式运行,如果当前存在事务,则抛出异常。
        NEVER(TransactionDefinition.PROPAGATION_NEVER),
    
        // 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于REQUIRED
        // 并非所有的TransactionManager都能支持这个传播级别
        NESTED(TransactionDefinition.PROPAGATION_NESTED);
    
    作者:whthomas
    链接:https://www.jianshu.com/p/e56b440e9eb6
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
    

    显然,这里需要使用REQUIRES_NEW传播行为。

    解决
    fail()方法上加上事务,并让propagation = REQUIRES_NEW

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    override fun fail() {
       saveLogToDB()
    }
    

    注意:同一个类中,方法间调用,事务AOP生效的前提条件是使用CGLIB方式实现AOP。

    相关文章

      网友评论

          本文标题:Spring 事务传播行为和隔离级别的应用

          本文链接:https://www.haomeiwen.com/subject/lxhmuftx.html