java - UserTransaction.rollback 异常 HHH000451

标签 java mysql hibernate jpa wildfly

我正在尝试实现两阶段原子提交或回滚模式。步骤是:

  1. 读取数据库并填充 UI 表单
  2. 在表单中输入更改,提交更新和应用程序级别验证
  3. 执行两个操作之一

    a.在一个事务中提交多个更改 b.回滚多个更改以放弃

这些步骤通过提交操作完成后效果很好,数据库读取,表单填充和更新,更改更新数据库。

当这些步骤通过回滚操作完成时,行为是相同的,除了在 userTransaction.rollback() 处抛出异常

[org.hibernate.engine.transaction.synchronization.internal.SynchronizationCallbackCoordinatorTrackingImpl](默认任务 30)HHH000451: 由后台线程调用的事务 afterCompletion;延迟 afterCompletion 处理,直到原始线程可以处理它。 [状态=4] (默认任务 30)sessionAbort ex org.hibernate.HibernateException:事务已在不同线程中回滚!

为什么我提交时没有抛出异常?表单的每个提交都有自己的线程,但我没有看到多线程问题。我不确定下一步该调查的重点在哪里。 MySql 或 Wildfly 或 JPA/Hibernate?

版本是:

  • java 版本“1.7.0_07”
  • ejb3
  • wildfly-8.2.0.Final
  • mysqladmin 版本 8.42 Distrib 5.5.21,适用于 x86_64 上的 Linux
  • RichFaces 4.5.4
  • 使用方言:org.hibernate.dialect.MySQL5Dialect

Sudo 代码是:

@TransactionManagement(TransactionManagementType.BEAN)
@Stateful(mappedName = "testSession")
@SessionScoped
@TransactionAttribute(value = TransactionAttributeType.REQUIRED)
public class TestSession {

@PersistenceContext(unitName="MySqlXA",type=PersistenceContextType.EXTENDED)    
private EntityManager entityManager;

@Resource private UserTransaction userTransaction;

First request/ thread one

    userTransaction.begin();    
    Query query = entityManager.createQuery(sqlQuery);
    List<SomeTable> queryResult = (List<SomeTable>)query.getResultList();
    populate a SessionScoped ManagedBean

    user think time
    make updates through the UI and submit

Second request / thread two

   TableOneRow tableOneRow = new TableOneRow(someStuff);
   TableTwoRow tableTwoRow = entityManager.find(otherStuff);

    entityManager.persist(tableOneRow);
    entitymanager.merge(tableTwoRow);

Third request / thread three submit for commit

   userTransaction.commit();

or Third request / thread three submit for abort

   userTransaction.rollback();

提前致谢

最佳答案

通过进一步的研究和实验,看起来丢弃一组更新的最干净的方法是调用entityManager.clear()。

请参阅下面的三个测试日志和相关代码。第一组查找、更新、提交是我良好更新的基线。第二组 find、update、abort 导致 HHH000451 异常。最后一位是中止部分,但使用 EntityManager 清除。

2017-03-23 16:48:55,425 DEBUG [view.TestPage] (default task-21) find
2017-03-23 16:48:55,426 TRACE [ejb.session.TestPageSession] (default task-21) findNameAddress for addrId 5
2017-03-23 16:48:55,426 TRACE [ejb.session.TestPageSession] (default task-21) entityManager.find
2017-03-23 16:48:55,465 TRACE [ejb.session.TestPageSession] (default task-21) findNameAddress success true

2017-03-23 16:49:49,714 DEBUG [view.TestPage] (default task-24) update
2017-03-23 16:49:49,714 TRACE [ejb.session.TestPageSession] (default task-24) updateFirstLastName to One, For
2017-03-23 16:49:49,715 TRACE [ejb.session.TestPageSession] (default task-24) userTransaction.begin
2017-03-23 16:49:49,716 TRACE [ejb.session.TestPageSession] (default task-24) userTransaction.begin success true
2017-03-23 16:49:49,716 TRACE [ejb.session.TestPageSession] (default task-24) findNameAddress for addrId 5
2017-03-23 16:49:49,716 TRACE [ejb.session.TestPageSession] (default task-24) entityManager.find
2017-03-23 16:49:49,716 TRACE [ejb.session.TestPageSession] (default task-24) findNameAddress success true
2017-03-23 16:49:49,716 TRACE [ejb.session.TestPageSession] (default task-24) entityManager.merge
2017-03-23 16:49:49,721 TRACE [ejb.session.TestPageSession] (default task-24) updateFirstLastName success true

2017-03-23 16:50:19,652 DEBUG [view.TestPage] (default task-25) commit
2017-03-23 16:50:19,654 TRACE [ejb.session.TestPageSession] (default task-25) userTransaction.commit
2017-03-23 16:50:19,726 TRACE [ejb.session.TestPageSession] (default task-25) userTransaction.commit success true

2017-03-23 16:50:50,740 DEBUG [view.TestPage] (default task-26) find
2017-03-23 16:50:50,741 TRACE [ejb.session.TestPageSession] (default task-26) findNameAddress for addrId 5
2017-03-23 16:50:50,741 TRACE [ejb.session.TestPageSession] (default task-26) entityManager.find
2017-03-23 16:50:50,741 TRACE [ejb.session.TestPageSession] (default task-26) findNameAddress success true

2017-03-23 16:51:12,735 DEBUG [view.TestPage] (default task-29) update
2017-03-23 16:51:12,735 TRACE [ejb.session.TestPageSession] (default task-29) updateFirstLastName to two, For
2017-03-23 16:51:12,735 TRACE [ejb.session.TestPageSession] (default task-29) userTransaction.begin
2017-03-23 16:51:12,736 TRACE [ejb.session.TestPageSession] (default task-29) userTransaction.begin success true
2017-03-23 16:51:12,736 TRACE [ejb.session.TestPageSession] (default task-29) findNameAddress for addrId 5
2017-03-23 16:51:12,736 TRACE [ejb.session.TestPageSession] (default task-29) entityManager.find
2017-03-23 16:51:12,736 TRACE [ejb.session.TestPageSession] (default task-29) findNameAddress success true
2017-03-23 16:51:12,736 TRACE [ejb.session.TestPageSession] (default task-29) entityManager.merge
2017-03-23 16:51:12,736 TRACE [ejb.session.TestPageSession] (default task-29) updateFirstLastName success true

2017-03-23 16:51:40,888 DEBUG [view.TestPage] (default task-30) abort
2017-03-23 16:51:40,889 TRACE [ejb.session.TestPageSession] (default task-30) userTransaction.rollback
2017-03-23 16:51:40,890 WARN  [org.hibernate.engine.transaction.synchronization.internal.SynchronizationCallbackCoordinatorTrackingImpl] (default task-30) HHH000451: Transaction afterCompletion called by a background thread; delaying afterCompletion processing until the original thread can handle it. [status=4]
2017-03-23 16:51:40,891 TRACE [ejb.session.TestPageSession] (default task-30) userTransaction.rollback success true



2017-03-23 16:54:08,623 DEBUG [view.TestPage] (default task-12) abort
2017-03-23 16:54:08,624 TRACE [ejb.session.TestPageSession] (default task-12) entityManager.clear
2017-03-23 16:54:08,625 TRACE [ejb.session.TestPageSession] (default task-12) entityManager.clear success true

package com.gregdata.session;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.faces.bean.SessionScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.transaction.UserTransaction;

import org.jboss.logging.Logger;

import com.gregdata.model.Nameaddress;

@TransactionManagement(TransactionManagementType.BEAN)
@Stateful(mappedName = "localTestSession")
@SessionScoped
@TransactionAttribute(value = TransactionAttributeType.REQUIRED)
public class TestPageSession implements TestPageSessionLocal {

@PersistenceContext(unitName="MySqlStocksXA",
                    type=PersistenceContextType.EXTENDED)   
private EntityManager entityManager;
@Resource private UserTransaction userTransaction;

private Nameaddress nameaddress;
private boolean transactionBegun;

private Logger logger;

public TestPageSession() {
    logger = Logger.getLogger(this.getClass());
}

@PostConstruct
public void initialize() {      
}

public EntityManager getEntityManager() {
    return entityManager;
}

public Nameaddress findNameaddress(int addrId)
{
    Nameaddress nameaddress = null;
    boolean success = false;

    logger.trace("findNameAddress for addrId "+addrId);

    try {
        logger.trace("entityManager.find");
        nameaddress = entityManager.find(Nameaddress.class, addrId);
        success = true;
    } catch (Exception ex)
    {
        logger.warn("findNameAddress ex: "+ex.getMessage());
        success = true;
    }

    logger.trace("findNameAddress success "+success);

    return nameaddress;
}

public boolean updateFirstLastName(int addrId, String firstName, String lastName)
{
    boolean success = false;

    logger.trace("updateFirstLastName to "+firstName+", "+lastName);

    try
    {
        beginTransaction();

        nameaddress = findNameaddress(addrId);
        if ( nameaddress == null)
        {
            throw new Exception("Nameaddress id "+addrId+" not found");
        }

        nameaddress.setFirstName(firstName);
        nameaddress.setLastName(lastName);
        logger.trace("entityManager.merge");
        entityManager.merge(nameaddress);

        success = true;

    } catch (Exception ex)
    {
        logger.warn("updateFirstLastName ex: "+ex.getMessage());
        success = false;            
    }

    logger.trace("updateFirstLastName success "+success);

    return success;

}

public boolean beginTransaction()
{

    boolean success = false;

    if (transactionBegun) return true;

    logger.trace("userTransaction.begin");

    try
    {
        userTransaction.begin();
        success = true;
        transactionBegun = true;        
    } catch(Exception ex)
    {
        logger.warn("userTransaction.begin ex "+ex.getMessage());
        success = false;        
    }

    logger.trace("userTransaction.begin success "+success);

    return success;
}

public boolean commitTransaction()
{
    boolean success = false;

    logger.trace("userTransaction.commit");

    try
    {           
        userTransaction.commit();           
        success = true;
        transactionBegun = false;
    } catch(Exception ex)
    {
        logger.warn("userTransaction.commit ex "+ex.getMessage());
        success = false;
        transactionBegun = false;
    }
    logger.trace("userTransaction.commit success "+success);

    return success;
}

public boolean abortTransaction()
{
    boolean success = false;

    logger.trace("userTransaction.rollback");

    try
    {
        userTransaction.rollback();
        success = true;
        transactionBegun = false;
    } catch(Exception ex)
    {
        logger.warn("userTransaction.rollback ex "+ex.getMessage());
        transactionBegun = false;
        success = false;
    }

    logger.trace("userTransaction.rollback success "+success);
    return success;     
}

public boolean clearEntityManager() {

    boolean success = false;

    logger.trace("entityManager.clear");

    try {
        entityManager.clear();
        success = true;
    } catch (Exception ex) {
        logger.warn("clearEntityManager ex: "+ex.getMessage());
    }
    logger.trace("entityManager.clear success "+success);

    return success;
}
}

关于java - UserTransaction.rollback 异常 HHH000451,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42847262/

相关文章:

java - 原始数组上的 Lambda

java - 如何从sqlite数据库中获取dd/mm/yyyy格式的两个日期之间的数据

mysql - 自动填充mysql表中的其他列

java - 映射到子表两次 - @OneToMany & @ManyToOne

java - 将 Spring/Hibernate 应用程序连接到 Docker 中运行的 Mysql

java聊天(服务器套接字/套接字)

java - @link 到 package-info.java 中的另一个包

mysql - 我无法从 sql 中的计数值获取最大值

android - android 设备上 sqlite 数据库的默认位置不显示我的数据库

java - Hibernate 一对多数据获取 - MySQLSyntaxErrorException