【问题标题】:Avoid Transaction rollback in Spring在 Spring 中避免事务回滚
【发布时间】:2017-03-06 02:10:42
【问题描述】:

假设我有下一个代码:

@Autowired
private IManager1 manager1;

@Autowired
private IManager2 manager2;

@Autowired
private IManager3 manager3;

@Transactional
public void run() {
     manager1.doStuff();
     manager2.registerStuffDone();

     manager3.doStuff();
     manager2.registerStuffDone();

     manager1.doMoreStuff();
     manager2.registerStuffDone();
}

如果出现任何异常,我想回滚“doStuff()”方法所做的一切,但我不想回滚“registerStuffDone()”方法记录的数据。

我一直在阅读@Transactional注解的传播选项,但我不明白如何正确使用它们。

每个经理在内部都使用 hiberante 来提交更改:

@Autowired
private IManager1Dao manager1Dao;

@Transactional
public void doStuff() {
    manager1Dao.doStuff();
}

道看起来像这样:

@PersistenceContext
protected EntityManager entityManager;

public void doStuff() {
    MyObject whatever = doThings();
    entityManager.merge(whatever);
}

这是我的 applicationContext 配置:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSourcePool" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
</bean>

<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>

想法?

【问题讨论】:

    标签: java spring jpa jdbc


    【解决方案1】:

    您需要 2 个事务,一个用于提交内容,一个用于回滚内容。

    @Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor={Exception1.class, Exception2.class})
    public void registerStuffDone()() {
       //code
    }
    

    然后,您的 run 方法将使用第一个事务并将回滚,但 registerStuffDone 方法将启动将提交的第二个事务。

    【讨论】:

    • 我尝试了 Propagation.REQUIRES_NEW 但它一直使用相同的事务。我添加了我的 applicationContext 配置,以防万一有什么影响到这个问题。
    • 我相信这会奏效。配置对我来说是正确的,为什么不切换日志并运行单元测试?
    • 你是对的!这就是诀窍。在实际项目中,主应用程序和示例管理器之间还有另一个管理器。我试图将@Transactional(propagation = Propagation.REQUIRED_NEW) 添加到这个中间方法中,但是就像我的manager2 已经有注释@Transactional 一样,这会覆盖父级中定义的所有内容。我很傻,我以前没有检查过!谢谢。
    • Propagation.NOT_SUPPORTED 如果内部方法调用/事务不持久,也是一个选项。就我而言,我的内部事务正在调用可选的外部服务,而不是与我的数据库交互。
    【解决方案2】:

    您正在使用声明式事务并希望像程序意义一样进行控制。出于这个原因,您需要更多地练习和深入了解Spring事务定义,例如PROPAGATION,ISOLATION等......

    程序化事务管理:这意味着您已经在编程的帮助下管理事务。这为您提供了极大的灵活性,但很难维护。
    Vs
    声明式事务管理:这意味着您将事务管理与业务代码分开。您只使用注释或基于 XML 的配置来管理事务。

    也许,通过程序化事务管理来解决您的问题。

    /** DataSourceTransactionManager */
        @Autowired
        private PlatformTransactionManager txManager;
    
        public void run() {
        try {
    
             // Start a manual transaction.
             TransactionStatus status = getTransactionStatus();
    
             manager1.doStuff();
             manager2.registerStuffDone();
    
             manager3.doStuff();
             manager2.registerStuffDone();
    
             manager1.doMoreStuff();
             manager2.registerStuffDone();
    
            //your condition 
            txManager.commit(status);
            //your condition 
            txManager.rollback(status);
    
             } catch (YourException e) {
    
            }       
        }    
    
    /**
         * getTransactionStatus
         *
         * @return TransactionStatus
         */
        private TransactionStatus getTransactionStatus() {
            DefaultTransactionDefinition dtd = new DefaultTransactionDefinition();
            dtd.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            dtd.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
            dtd.setReadOnly(false);
    
            return txManager.getTransaction(dtd);
        }
    

    注意:这并不意味着您需要始终使用一种方法,例如程序化事务管理。我更喜欢混合方法。对于简单的数据库服务,请使用声明式事务之类的简单方法,否则,只需在服务中使用程序化事务进行控制即可轻松节省您的逻辑。

    【讨论】:

    • 感谢您的回答,这很有启发性。但是我可以在最后用注释修复它。
    • 很高兴听到!太好了!
    猜你喜欢
    • 1970-01-01
    • 2011-11-21
    • 1970-01-01
    • 2016-09-19
    • 2017-03-03
    • 2012-03-10
    • 2018-07-15
    • 2018-11-05
    相关资源
    最近更新 更多