Aspectj 编译时基于编织的事务不起作用(来自 WebService 调用的 JPA)
我正在尝试使用aspectj 和编译时编织来支持Spring 的@Transactional 和@Configurable 等注释。我正在使用 org.springframework.orm.jpa.JpaTransactionManager 事务管理器,当我尝试在 GenericDAO 中调用entityManager.persist(entity) 时,我在日志中看到的内容是这样的:
insurance-module-0.1-SNAPSHOT 19:57:55.199 [http-bio-8084-exec-49] TRACE org.hibernate.loader.Loader - Bound [6] parameters total
insurance-module-0.1-SNAPSHOT 19:57:55.199 [http-bio-8084-exec-49] TRACE org.hibernate.loader.Loader - processing result set
insurance-module-0.1-SNAPSHOT 19:57:55.199 [http-bio-8084-exec-49] DEBUG org.hibernate.loader.Loader - result set row: 0
insurance-module-0.1-SNAPSHOT 19:57:55.199 [http-bio-8084-exec-49] TRACE o.h.t.descriptor.sql.BasicExtractor - found [1] as column [id3_]
insurance-module-0.1-SNAPSHOT 19:57:55.199 [http-bio-8084-exec-49] DEBUG org.hibernate.loader.Loader - result row: EntityKey[com.vendio.insurance.domain.db.InsuranceRate#1]
insurance-module-0.1-SNAPSHOT 19:57:55.199 [http-bio-8084-exec-49] TRACE org.hibernate.loader.Loader - done processing result set (1 rows)
insurance-module-0.1-SNAPSHOT 19:57:55.200 [http-bio-8084-exec-49] TRACE org.hibernate.loader.Loader - total objects hydrated: 0
insurance-module-0.1-SNAPSHOT 19:57:55.200 [http-bio-8084-exec-49] DEBUG o.h.e.StatefulPersistenceContext - initializing non-lazy collections
insurance-module-0.1-SNAPSHOT 19:57:55.200 [http-bio-8084-exec-49] TRACE org.hibernate.impl.SessionImpl - after transaction completion
insurance-module-0.1-SNAPSHOT 19:57:55.201 [http-bio-8084-exec-49] TRACE o.s.t.s.TransactionSynchronizationManager - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@5ec859c1] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@337cbe84] bound to thread [http-bio-8084-exec-49]
insurance-module-0.1-SNAPSHOT 19:57:55.209 [http-bio-8084-exec-49] DEBUG org.hibernate.SQL - select sequence_next_hi_value from hibernate_sequences where sequence_name = 'registered_policy' for update
insurance-module-0.1-SNAPSHOT 19:57:55.210 [http-bio-8084-exec-49] DEBUG org.hibernate.SQL - update hibernate_sequences set sequence_next_hi_value = ? where sequence_next_hi_value = ? and sequence_name = 'registered_policy'
insurance-module-0.1-SNAPSHOT 19:57:55.218 [http-bio-8084-exec-49] TRACE o.s.t.s.TransactionSynchronizationManager - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@5ec859c1] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@337cbe84] bound to thread [http-bio-8084-exec-49]
所以每个表休眠序列已更新,但我的实体未插入数据库。
如果我添加entityManager.flush(),则会出现异常,指出“没有事务正在进行”。
这里发生了什么?!
我的 GenericDAO 类如下所示:
public class GenericDAO<T extends Persistable> {
@PersistenceContext
protected EntityManager entityManager;
@PersistenceUnit
protected EntityManagerFactory entityManagerFactory;
@Transactional
public void saveOrUpdate(T entity) {
entityManager.persist(entity);
}
}
我从使用 WSSpringServlet。
PS:我的 Maven 配置也看起来像这样:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.4</version>
<configuration>
<complianceLevel>1.6</complianceLevel>
<showWeaveInfo>true</showWeaveInfo>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
编译时,我得到了一些看起来足够不错的东西(我的方面被应用):
Join point 'method-call(void javax.persistence.EntityManager.persist(java.lang.Object))'
in Type 'com.vendio.insurance.dao.GenericDAO' (GenericDAO.java:28)
advised by afterThrowing advice from 'org.springframework.orm.jpa.aspectj.JpaExceptionTranslatorAspect'
(spring-aspects-3.1.0.RELEASE.jar!JpaExceptionTranslatorAspect.class:14(from JpaExceptionTranslatorAspect.aj))
我的相关 Spring 配置是:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<context:component-scan base-package="com.vendio.insurance" />
<context:spring-configured/>
<!-- <bean class="org.springframework.transaction.aspectj.AnnotationTransactionAspect" factory-method="aspectOf">
<property name="transactionManager" ref="transactionManager"/>
</bean>-->
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />
所以一切看起来都不错,但我找不到为什么这不正确的答案不工作...
I'm trying to use aspectj with compile time weaving to support annotations like Spring's @Transactional and @Configurable. I'm using the org.springframework.orm.jpa.JpaTransactionManager transaction manager and what I see in the logs when I try to call entityManager.persist(entity) in my GenericDAO is something like this:
insurance-module-0.1-SNAPSHOT 19:57:55.199 [http-bio-8084-exec-49] TRACE org.hibernate.loader.Loader - Bound [6] parameters total
insurance-module-0.1-SNAPSHOT 19:57:55.199 [http-bio-8084-exec-49] TRACE org.hibernate.loader.Loader - processing result set
insurance-module-0.1-SNAPSHOT 19:57:55.199 [http-bio-8084-exec-49] DEBUG org.hibernate.loader.Loader - result set row: 0
insurance-module-0.1-SNAPSHOT 19:57:55.199 [http-bio-8084-exec-49] TRACE o.h.t.descriptor.sql.BasicExtractor - found [1] as column [id3_]
insurance-module-0.1-SNAPSHOT 19:57:55.199 [http-bio-8084-exec-49] DEBUG org.hibernate.loader.Loader - result row: EntityKey[com.vendio.insurance.domain.db.InsuranceRate#1]
insurance-module-0.1-SNAPSHOT 19:57:55.199 [http-bio-8084-exec-49] TRACE org.hibernate.loader.Loader - done processing result set (1 rows)
insurance-module-0.1-SNAPSHOT 19:57:55.200 [http-bio-8084-exec-49] TRACE org.hibernate.loader.Loader - total objects hydrated: 0
insurance-module-0.1-SNAPSHOT 19:57:55.200 [http-bio-8084-exec-49] DEBUG o.h.e.StatefulPersistenceContext - initializing non-lazy collections
insurance-module-0.1-SNAPSHOT 19:57:55.200 [http-bio-8084-exec-49] TRACE org.hibernate.impl.SessionImpl - after transaction completion
insurance-module-0.1-SNAPSHOT 19:57:55.201 [http-bio-8084-exec-49] TRACE o.s.t.s.TransactionSynchronizationManager - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@5ec859c1] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@337cbe84] bound to thread [http-bio-8084-exec-49]
insurance-module-0.1-SNAPSHOT 19:57:55.209 [http-bio-8084-exec-49] DEBUG org.hibernate.SQL - select sequence_next_hi_value from hibernate_sequences where sequence_name = 'registered_policy' for update
insurance-module-0.1-SNAPSHOT 19:57:55.210 [http-bio-8084-exec-49] DEBUG org.hibernate.SQL - update hibernate_sequences set sequence_next_hi_value = ? where sequence_next_hi_value = ? and sequence_name = 'registered_policy'
insurance-module-0.1-SNAPSHOT 19:57:55.218 [http-bio-8084-exec-49] TRACE o.s.t.s.TransactionSynchronizationManager - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@5ec859c1] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@337cbe84] bound to thread [http-bio-8084-exec-49]
so the per-table hibernate sequence gets updated but my entity is not inserted into the database.
If I add entityManager.flush() an exception appears stating "no transaction is in progress".
What is going on here?!
My GenericDAO class looks like this:
public class GenericDAO<T extends Persistable> {
@PersistenceContext
protected EntityManager entityManager;
@PersistenceUnit
protected EntityManagerFactory entityManagerFactory;
@Transactional
public void saveOrUpdate(T entity) {
entityManager.persist(entity);
}
}
I call the saveOrUpdate method from a web-service exported with the WSSpringServlet.
P.S.: Also my Maven config looks like this:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.4</version>
<configuration>
<complianceLevel>1.6</complianceLevel>
<showWeaveInfo>true</showWeaveInfo>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
When compiling I get something which looks decent enough (my aspect gets applied):
Join point 'method-call(void javax.persistence.EntityManager.persist(java.lang.Object))'
in Type 'com.vendio.insurance.dao.GenericDAO' (GenericDAO.java:28)
advised by afterThrowing advice from 'org.springframework.orm.jpa.aspectj.JpaExceptionTranslatorAspect'
(spring-aspects-3.1.0.RELEASE.jar!JpaExceptionTranslatorAspect.class:14(from JpaExceptionTranslatorAspect.aj))
And my relevant Spring config is:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<context:component-scan base-package="com.vendio.insurance" />
<context:spring-configured/>
<!-- <bean class="org.springframework.transaction.aspectj.AnnotationTransactionAspect" factory-method="aspectOf">
<property name="transactionManager" ref="transactionManager"/>
</bean>-->
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />
So everything looks decent, but I can't find an answer of why this doesn't work...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我在以下链接中找到了答案: http://forum.springsource .org/showthread.php?18953-DispatcherServlet-and-ContextLoaderListener。
问题是由于我也在使用 Spring MVC 并且我在不知道两个几乎相同的 Spring 上下文的情况下进行创建。因此,事务由第一个上下文(接收 JAX-WS 调用的上下文)中的事务管理器管理,但我调用的实体管理器由第二个上下文(具有不同的事务管理器)管理。
解决方案是隔离 DispatcherServlet 的小型简化上下文定义,并让其余的 Bean 由 ContextLoaderListener 管理:
由于我使用基于注释的 MVC(带有 @Controller 注释),所以我还必须缩小 context:component 的范围-扫描“servlet”上下文中的基础包。
以下是拯救我的链接中的引用:
I've found my answer following this link: http://forum.springsource.org/showthread.php?18953-DispatcherServlet-and-ContextLoaderListener.
The problem was caused by the fact that I was also using Spring MVC and I was creating without knowing two almost identical Spring contexts. Thus the transaction was managed by the transaction manager in the first context (the one receiving the JAX-WS call) but the entity manager I was calling was managed by the second context (with a different transaction manager).
The solution was to isolate the small reduced context definition for the DispatcherServlet and leave the rest of the beans to be managed by ContextLoaderListener:
Since I used annotation based MVC (with @Controller annotation) I also had to reduce the scope of the context:component-scan's base-package in the "servlet" context.
Below is the quote from the link that saved my day:
如果您使用 EntityManager,您将不必处理代码中的任何休眠问题。
这正是 jpa 的用途。
前段时间我也遇到了同样的问题。
您的 EntityManager 必须注入 @PersistenceContext。 getEntityManager() 不行。
并且您带注释的函数必须是公开的。
If you use EntityManager you won't have to deal with any hibernate issues in your code.
That's exactly what jpa is for.
I had the same problem some time ago.
Your EntityManager has to be injected with @PersistenceContext. getEntityManager() won't do.
And your annotated functions have to be public.
即使两个相同的 Spring 上下文没有问题,我也遇到了相同的症状。 forceAjcCompile 选项解决了该问题:
I was experiencing the same symptom even though there was no problem of two identical Spring contexts. The forceAjcCompile option resolved the issue: