交易需要例外JPA / Spring

时间:2015-04-13 08:32:33

标签: java spring hibernate jpa transactions

我在存储库类中有一个标记为@Transactional的方法,正在堆栈跟踪中看到正在执行的方面,但抛出的异常是“Transaction required exception”

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

这是stacktrace:

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

配置:

EMF:

<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))上都可以完全正常,但它在Amazon EC2 Elasticbeanstalk(Tomcat 8)上引发了此错误,64位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

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

这是坚果。

修改 好吧,我发现了这行调试:

2015-04-13 15:27:44,174 [http-bio-8080-exec-2] DEBUG org.springframework.orm.jpa.JpaTransactionManager - 参与交易失败 - 将现有交易标记为仅回滚

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

似乎有一个事务被检查为已完成,并且加入事务失败,因此它将其标记为仅回滚,因为它无法加入它。

4 个答案:

答案 0 :(得分:5)

我更改了注释驱动的配置,只需添加 proxy-target-class =&#34; true&#34; 似乎修复了我们在亚马逊上海的一个环境(东南部)问题,但对于欧洲(欧洲西部),问题仍然存在。这是一场噩梦,所有配置完全相同(它只指向不同的db&amp; s3)

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

<击>

<强> SOLUTION:

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

<强>原因: 显然它与spring初始化有关,在初始化完成之前调度一些任务,并且搞砸了。

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

@Transactional(propagation = Propagation.REQUIRES_NEW)

从DAO图层中删除了@Transactional

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

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

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

<强> 备注 我还删除了之前的更改:&#34; proxy-target-class =&#34; true&#34; &#34;,它仍然正常工作,因此它们不是这真的是一个很好的解决方案,但它可能对你有用,就像它在某些情况下(背景任务)一样。

正如附注所示,我必须做的另一项改变是将@Repository更改为@Component,因为有些交易没有对数据库进行写入操作预定的任务。

答案 1 :(得分:3)

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

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

  

特别是,您不需要仅通过EJB进行声明式事务的应用程序服务器。事实上,即使你的应用服务器具有强大的JTA功能,你也可以决定Spring Framework的声明式事务提供更强大的功能,并且比EJB CMT更高效的编程模型。

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

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:0)

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