Spring data jpa嵌套事务回滚不删除插入?

Posted

技术标签:

【中文标题】Spring data jpa嵌套事务回滚不删除插入?【英文标题】:Spring data jpa nested transaction rollback not deleting insert? 【发布时间】:2017-02-22 13:31:25 【问题描述】:

我尝试在一个事务中在我的数据库中插入 2 条记录。第二次插入失败但在回滚中第一次插入没有被删除:

   @Resource
      private WebMessageRep rep; //<-- extends JpaRepository

@Transactional
  public void test() 
    WebMessage wm = new WebMessage(.valid params.);
    wm = rep.save(wm);//<-- save is crud save which is transactional by default
    WebMessage wm2 = new WebMessage(.invalid params.);
    rep.save(wm2);
  

(我也尝试将保存方法替换为: jpaContext.getEntityManagerByManagedType(WebMessage.class).persist(wm); 这样我就不用crud save了,但是问题依然存在)

我启用了事务日志以查看发生了什么,我发现:

在调用 test() 之前,会创建一个新事务,因为 @transactional 注释:

Creating new transaction with name [com..data.webmessage.WebMessageServiceImpl.test]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
 Opened new EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableListsize=0 updates=ExecutableListsize=0 deletions=ExecutableListsize=0 orphanRemovals=ExecutableListsize=0 collectionCreations=ExecutableListsize=0 collectionRemovals=ExecutableListsize=0 collectionUpdates=ExecutableListsize=0 collectionQueuedOps=ExecutableListsize=0 unresolvedInsertDependencies=null])] for JPA transaction

调用第一次保存,它会看到第一笔交易:

Found thread-bound EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableListsize=0 updates=ExecutableListsize=0 deletions=ExecutableListsize=0 orphanRemovals=ExecutableListsize=0 collectionCreations=ExecutableListsize=0 collectionRemovals=ExecutableListsize=0 collectionUpdates=ExecutableListsize=0 collectionQueuedOps=ExecutableListsize=0 unresolvedInsertDependencies=null])] for JPA transaction

第二次保存也看到第一笔交易:

Found thread-bound EntityManager [SessionImpl(PersistenceContext[entityKeys=[EntityKey[com..shared.WebMessage#107]],collectionKeys=[]];ActionQueue[insertions=ExecutableListsize=1 updates=ExecutableListsize=0 deletions=ExecutableListsize=0 orphanRemovals=ExecutableListsize=0 collectionCreations=ExecutableListsize=0 collectionRemovals=ExecutableListsize=0 collectionUpdates=ExecutableListsize=0 collectionQueuedOps=ExecutableListsize=0 unresolvedInsertDependencies=null])] for JPA transaction
2017-02-22 14:07:22,000 [           main] DEBUG orm.jpa.JpaTransactionManager             - Participating in existing transaction

退出 test() 时,提交完成:

 Committing JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[EntityKey[com..shared.WebMessage#108], EntityKey[com..shared.WebMessage#107]],collectionKeys=[]];ActionQueue[insertions=ExecutableListsize=2 updates=ExecutableListsize=0 deletions=ExecutableListsize=0 orphanRemovals=ExecutableListsize=0 collectionCreations=ExecutableListsize=0 collectionRemovals=ExecutableListsize=0 collectionUpdates=ExecutableListsize=0 collectionQueuedOps=ExecutableListsize=0 unresolvedInsertDependencies=null])]

失败了:

    Column 'text' cannot be null
 HHH000010: On release of batch it still contained JDBC statements
HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement]
    Initiating transaction rollback after commit exception

回滚:

Rolling back JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableListsize=0 updates=ExecutableListsize=0 deletions=ExecutableListsize=0 orphanRemovals=ExecutableListsize=0 collectionCreations=ExecutableListsize=0 collectionRemovals=ExecutableListsize=0 collectionUpdates=ExecutableListsize=0 collectionQueuedOps=ExecutableListsize=0 unresolvedInsertDependencies=null])]

奇怪的是,第一条插入的记录还在我的数据库(mysql)中。

不确定这是否意味着什么,但在提交时我们有: 插入=可执行列表大小=2 但在回滚时它是: 插入=ExecutableListsize=0

有人知道为什么它不回滚第一个插入吗?

我的交易配置很简单:

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="emf" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

启动我的调试器后发现我的事务在尝试回滚时不再处于活动状态。让我解释一下:

[JpaTransactionManager.java]

@Override
    protected void doRollback(DefaultTransactionStatus status) 
        JpaTransactionObject txObject = (JpaTransactionObject) status.getTransaction();
        if (status.isDebug()) 
            logger.debug("Rolling back JPA transaction on EntityManager [" +
                    txObject.getEntityManagerHolder().getEntityManager() + "]");
        
        try 
            EntityTransaction tx = txObject.getEntityManagerHolder().getEntityManager().getTransaction();
            if (tx.isActive()) 
                tx.rollback();
            
        
        catch (PersistenceException ex) 
            throw new TransactionSystemException("Could not roll back JPA transaction", ex);
        
        finally 
            if (!txObject.isNewEntityManagerHolder()) 
                // Clear all pending inserts/updates/deletes in the EntityManager.
                // Necessary for pre-bound EntityManagers, to avoid inconsistent state.
                txObject.getEntityManagerHolder().getEntityManager().clear();
            
        
    

上面代码中的tx.isActive()返回false,表示不执行回滚。

现在最大的问题是为什么我的交易不再活跃?

【问题讨论】:

【参考方案1】:

看来问题出在mysql上,spring data jpa生成的表是myisam类型的。

似乎 myisam 在使用某些类型的事务时变得不稳定。

我将我的表转换为 innodb,现在它可以工作了:当事务失败并且事务回滚时,所有​​插入的行都将被删除。当 table 是 myisam 类型时,不会发生这种情况。

【讨论】:

以上是关于Spring data jpa嵌套事务回滚不删除插入?的主要内容,如果未能解决你的问题,请参考以下文章

Spring启动集成测试回滚不起作用

SQL Server CE 回滚不撤消删除

@Transactional注解事务不回滚不起作用无效

Spring @Transactional注解不回滚不起作用无效

Spring @Transactional 和回滚不起作用,弹簧集成测试

使用JPA的Spring数据不会在出错时回滚事务