【问题标题】:Transaction required exception JPA / Spring事务需要异常 JPA / Spring
【发布时间】:2015-06-18 12:14:11
【问题描述】:

我在存储库类中有一个标记为@Transactional 的方法,正在执行方面,如堆栈跟踪中所示,但抛出的异常是“需要事务的异常”

我将@Repository 注释更改为@Component(在某些情况下似乎解决了这个问题),但它仍然发生在网络角色上。

这是堆栈跟踪:

2015-04-13 08:00:56,497 [http-nio-8080-exec-9] WARN  es.mycompany.util.filters.MyFilter - Error storing : /admin/online/update
org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
        at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:410)
        at org.springframework.orm.jpa.aspectj.JpaExceptionTranslatorAspect.ajc$afterThrowing$org_springframework_orm_jpa_aspectj_JpaExceptionTranslatorAspect$1$18a1ac9(JpaExceptionTranslatorAspect.aj:37)
        at es.mycopmany.dao.MyDAO.updateLastUpdatedTs_aroundBody2(MyDAO.java:36)
        at es.mycopmany.dao.MyDAO$AjcClosure3.run(MyDAO.java:1)
        at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(AbstractTransactionAspect.aj:66)
        at org.springframework.transaction.aspectj.AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation(AbstractTransactionAspect.aj:72)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
        at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:70)
        at es.mycompany.dao.MyDAO.updateLastUpdatedTs(MyDAO.java:31)

这里是抛出异常的代码:

    @Transactional
    public void updateLastUpdatedTs(String id, Calendar date) {
        Query query = entityManager.createQuery("update MyEntity set lastUpdatedTs = :ts "
                + " where id= :id");
        query.setParameter("ts", date);
        query.setParameter("id", id);
        query.executeUpdate();
    }

事务注解来自org.springframework.transaction.annotation.Transactional

版本:

Spring: 4.1.5.RELEASE 
Hibernate: 4.3.8.Final 
Aspectj: 1.8.5 
Tomcat 8.0.20

配置:

电磁场:

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
        id="entityManagerFactory">
        <property name="persistenceUnitName" value="athena" />
        <property name="dataSource" ref="dataSource" />
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
        </property>
    </bean>

交易:

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

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

我真的要疯了,任何帮助都会很棒。

请注意,这一切在我的开发环境(Windows、Idea Tomcat 8、JDK 8.0.31 (Oracle's) 上完全正常工作,但它在 Amazon EC2 Elasticbeanstalk (Tomcat 8 , 64bit Amazon Linux 2015.03, Open JDK 8.0.31 (尝试使用Oracle的8.0.40)

编辑:更多信息:在整个过滤器链末尾的过滤器上引发异常。

这是异常之前的一些调试信息:

2015-04-13 14:57:48,578 [http-bio-8080-exec-7] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Creating new transaction with name [MyService.myMethod]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2015-04-13 14:57:48,578 [http-bio-8080-exec-7] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@33f67ee5] for JPA transaction
2015-04-13 14:57:48,580 [http-bio-8080-exec-7] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@3112368a]
2015-04-13 14:57:48,581 [http-bio-8080-exec-7] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@3193771b] for key [HikariDataSource (HikariPool-1)] to thread [http-bio-8080-exec-7]
2015-04-13 14:57:48,581 [http-bio-8080-exec-7] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [org.springframework.orm.jpa.EntityManagerHolder@497d4e44] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@5019da97] to thread [http-bio-8080-exec-7]
2015-04-13 14:57:48,581 [http-bio-8080-exec-7] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Initializing transaction synchronization
2015-04-13 14:57:48,581 [http-bio-8080-exec-7] TRACE org.springframework.transaction.aspectj.AnnotationTransactionAspect - Getting transaction for [MyService.myMethod]
2015-04-13 14:57:48,581 [http-bio-8080-exec-7] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@497d4e44] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@5019da97] bound to thread [http-bio-8080-exec-7]
2015-04-13 14:57:48,581 [http-bio-8080-exec-7] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Found thread-bound EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@33f67ee5] for JPA transaction
2015-04-13 14:57:48,581 [http-bio-8080-exec-7] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@3193771b] for key [HikariDataSource (HikariPool-1)] bound to thread [http-bio-8080-exec-7]
2015-04-13 14:57:48,581 [http-bio-8080-exec-7] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Participating in existing transaction
2015-04-13 14:57:48,581 [http-bio-8080-exec-7] TRACE org.springframework.transaction.aspectj.AnnotationTransactionAspect - Getting transaction for [MyDao.updateLastUpdatedTs]
2015-04-13 14:57:48,581 [http-bio-8080-exec-7] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils - Opening JPA EntityManager
2015-04-13 14:57:48,582 [http-bio-8080-exec-7] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils - Registering transaction synchronization for JPA EntityManager
2015-04-13 14:57:48,582 [http-bio-8080-exec-7] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [org.springframework.orm.jpa.EntityManagerHolder@4f83552c] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@7cc8111c] to thread [http-bio-8080-exec-7]
2015-04-13 14:57:48,608 [http-bio-8080-exec-7] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@4f83552c] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@7cc8111c] bound to thread [http-bio-8080-exec-7]
2015-04-13 14:57:48,608 [http-bio-8080-exec-7] TRACE org.springframework.transaction.aspectj.AnnotationTransactionAspect - Completing transaction for [MyDao.updateLastUpdatedTs] after exception: org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query

实际上是说,它创建了Transaction,然后加入了事务(现在有两个@Transactionals,一个在服务层,一个在DAO层),然后回滚事务,由于一个例外“需要交易”。

这太疯狂了。

编辑 嗯,我找到了这行调试:

2015-04-13 15:27:44,074 [http-bio-8080-exec-2] 调试 org.springframework.orm.jpa.JpaTransactionManager - 参与事务失败 - 将现有事务标记为仅回滚

这里的值是:propagation=REQUIRED,isolation=DEFAULT

好像有一个事务,被检查为已完成,加入事务失败,所以只标记为回滚,因为无法加入。

【问题讨论】:

    标签: java spring hibernate jpa transactions


    【解决方案1】:

    我更改了注释驱动的配置,只需添加 proxy-target-class="true" 似乎已经解决了我们的一个问题环境(ap-southeast)是亚马逊上海,但至于欧洲(eu-west),问题仍然存在。这是一场噩梦,所有的配置都一模一样(只是指向不同的db & s3)

    <tx:annotation-driven mode="aspectj" proxy-target-class="true" transaction-manager="transactionManager" />
    

    解决方案:

    毕竟,我终于得到了一些东西。这解决了它(至少显然)。

    原因: 显然它与spring初始化有关,并在初始化完成之前安排了一些任务,并且有些事情搞砸了。

    我使用 REQUIRES_NEW 传播在服务层设置事务注释,以强制创建新事务。

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    

    从 DAO 层中删除了@Transactional。

    我还必须对连接器进行一些更改,增加 maxThreads 和最大/最小备用线程。

    我还将我所有的@Scheduled 初始化任务更改为在 tomcat 启动后 10 分钟启动

    在所有这些更改之后,错误消失了。

    备注 我还删除了之前的更改:“proxy-target-class="true"”,它仍然可以正常工作,所以这不是一个很好的修复,但它可能对你有用就像在某些情况下(后台任务)对我所做的那样。

    作为旁注,为了完成这项工作,我必须做的另一项更改是将 @Repository 更改为 @Component,因为某些事务没有在计划任务上写入数据库。

    【讨论】:

    • 您可以接受自己的答案。 +1 发布答案。
    • 它不允许我,它说不能在 2 天内。但无论如何,这已经解决了我们的亚洲环境(ap-southeast)的问题,而不是欧洲(eu-west)的问题,这让我非常抓狂。所有配置完全相同。
    • 包括底层SQL数据库的准确配置吗?
    • 是的,不同的实例(每个区域一个),不同的大小(实例大小),但相同的 RDS 具有相同的参数组(相同的参数)。数据库不是解决方案中描述的问题。不过谢谢。
    【解决方案2】:

    不是春天的专家,但希望这会有所帮助。

    几天前,阅读Spring documentation 的类似问题,我发现:

    特别是,您不需要应用程序服务器来简单地通过 EJB 进行声明性事务。事实上,即使您的应用程序服务器具有强大的 JTA 功能,您也可能认为 Spring 框架的声明式事务提供了比 EJB CMT 更强大的功能和更高效的编程模型。

    AFAIK,在我们的服务中,我们更具体地声明交易以避免一些此类问题,例如:

    @Transactional
    (
        propagation = Propagation.REQUIRED, 
        readOnly = false,
        rollbackFor = Throwable.class
    )
    

    如果您的注释仅适用于某些服务器,请在声明时尝试具体说明以涵盖您的事务场景。通过这种方式,我猜您将在所有服务器上实现相同的行为。

    【讨论】:

    • 我们不使用 JTA。 @Transactional 注释已经有一些默认值。注释有效,因为它会触发 AnnotationSupportAspect,但仍然会引发异常。感谢您的帮助
    【解决方案3】:

    我刚刚遇到了同样的问题。原来,我试图在动态创建的后台线程中使用类范围定义的 EntityManager,这导致了异常。没有关于此问题的其他错误消息,并且堆栈跟踪指向 query.executeUpdate(),因此解决此问题有点困难。回到串行处理使错误消失。

    【讨论】:

    • 我的问题确实与后台线程和等待初始化有关。
    【解决方案4】:

    我认为这个问题在最新版本的 spring 中已经解决了。只需在我的服务类顶部添加 @Transactional 注释对我有用。

    【讨论】:

    • 请记住,该错误依赖于在 spring 初始化之前触发的计划任务。也许它已修复在较新的版本上。我真的不能说,这已经是很久以前的事了。一些交易运行良好,而且仅在 AWS 中发生。也许是因为他们的 coretto jdk,我现在不确定。
    猜你喜欢
    • 2023-03-18
    • 2018-02-04
    • 2021-10-03
    • 2016-02-13
    • 2013-04-15
    • 1970-01-01
    • 2016-07-30
    • 2018-01-14
    • 2012-04-14
    相关资源
    最近更新 更多