当前位置: 首页 > 知识库问答 >
问题:

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

谷梁宁
2023-03-14

我试图在一个事务中插入两个记录到我的数据库中。第二次插入失败,但是在回滚中第一次插入没有被删除:

   @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);
  }

(我还尝试将save方法替换为:jpaContext.getEntityManagerByManagedType(WebMessage.class)。坚持(wm);因此,我不使用crud保存,但问题仍然存在)

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

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

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

调用first save,它会看到第一个事务:

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

第二次保存也会看到第一个事务:

Found thread-bound EntityManager [SessionImpl(PersistenceContext[entityKeys=[EntityKey[com..shared.WebMessage#107]],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=1} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=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=ExecutableList{size=2} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=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=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]

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

不确定它是否意味着什么,但在提交时我们有:插入=可执行列表{大小=2},但在回滚时是:插入=可执行列表{大小=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个答案

邬浩涆
2023-03-14

看起来问题出在mysql上,Spring data jpa生成的表属于myisam类型。

当使用某些类型的交易时,myisam似乎变得不稳定。

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

 类似资料:
  • 在服务中定义了一个事务性函数,并从一个调度任务调用它,在这个函数中,对同一对象进行了两轮插入,在第二轮插入过程中,由于重复键的存在,会引发异常。我已经将事务注释配置为针对抛出的异常进行回滚,并且打开了log4j springframework日志,从日志中我可以看到事务管理器正在对回滚进行一些操作,例如确定是否对抛出的异常进行回滚,但是我看不到任何正在进行数据库删除操作的日志,并且检查数据库显示回

  • 我们为JPA配置了Spring数据。服务事务方法不会因错误而回滚(例如,DB ConstraintViolationException)。 我能找到的最接近的是这个(事务不回滚)Spring-data、JTA、JPA、Wildfly10但是我们没有任何XML配置,我们所有的配置都是基于Java的。 本质上,服务方法如下所示:不捕获错误,抛出所有内容。

  • 情景故事时间: 我“继承”了一个程序,一个用于访问数据库的相当简单的webservice。该程序在某个地方有一个缺陷:它试图更新一个没有更新授权的表。该程序只具有更新数据库队列的权限(Oracle),以保存谁访问了什么信息。这是不受欢迎的行为,现在我纠正了它。注意:这与这个问题本身无关,它只是导致我提出这个问题的原因。 该程序使用Spring+Hibernate来管理和访问数据和事务。 因为程序的

  • 我试图编写一个spring-cloud-stream函数(spring-starter-parent 2.5.3,java 11,spring-cloud-version 2020.0.3),该函数同时具有Kafka和Postgres事务。每当使用的消息以字符串“fail”开始时,该函数将引发一个模拟错误,我希望这将导致数据库事务回滚,然后导致kafka事务回滚。(我知道Kafka交易不是XA,这

  • 我有一个类,它有一个方法,该方法调用另一个服务上的另一个方法。大概是这样的: 我预计一个实体将被插入,但是如果任何嵌套事务抛出异常插入将拒绝,即使这个异常也是在处理的。 我可以用注释。但它会胜过表演。

  • 我们有一个Spring事务回滚问题,其中回滚似乎不起作用 在用注释的服务层方法中,我调用三个不同的类来插入3条记录 中间插入从第四个表执行get以填充描述字段,但此get失败。我希望第一次插入会回滚,但它似乎没有发生 几点: 获取方法抛出运行时异常 我们使用和中定义的。Bean是在中创建的,它被导入到 在层 中没有 注释 我们已经使用了