更新时的TransactionRequiredException

时间:2019-06-18 11:38:48

标签: java spring jpa entitymanager

我在日志中得到了异常:

  

javax.persistence.TransactionRequiredException:执行更新/删除查询

这位于isNew = false方法的updateSomething()分支中。我没有发现其他分支机构的例外情况。

我在stackoverflow上发现了一些有关使用entityManager.joinTransaction();的信息,但是当我这样做时,又遇到了另一个异常:

  

java.lang.IllegalStateException:不允许在共享的EntityManager上加入事务

我想正确处理此问题,以便updateSomething方法起作用。我还想知道嵌套@Transactional注释是否是一个好主意,以及从事务方法调用事务方法的效果是什么-我相信内部事务在其自己的事务中运行并提交到数据库。

注意:HACK不起作用,我将其保留为我尝试过的示例。

想法:每次更新(使用本机SQL的更新)之后执行entityManager.flush()会有所帮助吗?

@Transactional
public boolean generateLogsComposite() {
    Connection conn = getConnection();
    writeSomeData(conn);//write some data using a separate connection
    boolean isNew = checkSomeData();//The check works with the data from writeSomeData although not using he connection conn
    if(isNew) {
        generateEmail(conn);//Calls a stored procedure on connection conn.
        updateRunEnvOnEmail(emailId, runEnv);
        //Now the data from generateEmail and updateRunEnvOnEmail is present
    } else {
        updateSomething();//has a javax.persistence.TransactionRequiredException: Executing an update/delete query
    }
}

private void joinTransaction() {
    try {
        //HACK vs javax.persistence.TransactionRequiredException: Executing an update/delete query
        entityManager.joinTransaction();
        logger.debug("Joined transaction successfully");
    } catch(Throwable t) {
        //java.lang.IllegalStateException: Not allowed to join transaction on shared EntityManager
    }
}

@Transactional
public void updateRunEnvOnEmail(Long emailId, String runEnv)
{
    try
    {
        //HACK vs javax.persistence.TransactionRequiredException: Executing an update/delete query
        joinTransaction();

        Query query = entityManager
                .createNativeQuery("update XXX.EMAIL e set e.RUN_ENVIRONMENT = :runEnv where e.EMAIL_ID = :emailId");
        query.setParameter("runEnv", runEnv);
        query.setParameter("emailId", emailId);
        query.executeUpdate();
    } catch (Exception e)
    {
        logger.debug("Error while updating RUN_ENVIRONMENT on Email : "
                + emailId + " ::: " + e);
    }

}

@Transactional
public void updateSomething()
{
    try
    {
        //HACK vs javax.persistence.TransactionRequiredException: Executing an update/delete query
        joinTransaction();

        Query query = entityManager
                .createNativeQuery("update something");
        query.executeUpdate();
    } catch (Exception e)
    {
        logger.debug("Error while updating something",e);
    }

}

1 个答案:

答案 0 :(得分:1)

通常,除非明确配置,否则JPA不希望在事务外部调用更新。正确的方法如下:

entityManager.getTransaction().begin();
// do your updates
entityManager.getTransaction().commit();

但是,如果您希望由Spring管理交易(您的IllegalStateException如此建议),那么您可能希望研究@Transactional(但是请确保提供正确的交易管理器,想查看TransactionRequiredException Executing an update/delete query的答案以获取见识。