Aspectj 编译时基于编织的事务不起作用(来自 WebService 调用的 JPA)

发布于 2025-01-01 18:31:11 字数 5236 浏览 5 评论 0原文

我正在尝试使用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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

つ可否回来 2025-01-08 18:31:11

我在以下链接中找到了答案: http://forum.springsource .org/showthread.php?18953-DispatcherServlet-and-ContextLoaderListener

问题是由于我也在使用 Spring MVC 并且我在不知道两个几乎相同的 Spring 上下文的情况下进行创建。因此,事务由第一个上下文(接收 JAX-WS 调用的上下文)中的事务管理器管理,但我调用的实体管理器由第二个上下文(具有不同的事务管理器)管理。

解决方案是隔离 DispatcherServlet 的小型简化上下文定义,并让其余的 Bean 由 ContextLoaderListener 管理:

<listener> 
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 
<context-param> 
 <param-name>contextConfigLocation</param-name> 
 <param-value>/WEB-INF/spring/application-context.xml</param-value> 
</context-param>

<servlet> 
 <servlet-name>spring-mvc-dispatcher-servlet</servlet-name> 
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>2</load-on-startup> 
 <init-param> 
 <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/servlet-context.xml</param-value> 
 </init-param> 
</servlet> 

由于我使用基于注释的 MVC(带有 @Controller 注释),所以我还必须缩小 context:component 的范围-扫描“servlet”上下文中的基础包。

以下是拯救我的链接中的引用:

DispatcherServlet 将始终使用 -servlet.xml 加载自己的配置文件。该文件旨在包含控制器、ViewResolvers 和 LocaleResolvers 等 Web 组件,但不包含中间层组件。

然后使用 ContextLoaderListener 加载包含中间层和数据层组件的文件。 Spring 会将所有这些组件合并到 ApplicationContext 中,使您的中间层组件可以从 Web 层组件访问。 >Rob Harrop dm 服务器首席工程师

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:

<listener> 
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 
<context-param> 
 <param-name>contextConfigLocation</param-name> 
 <param-value>/WEB-INF/spring/application-context.xml</param-value> 
</context-param>

<servlet> 
 <servlet-name>spring-mvc-dispatcher-servlet</servlet-name> 
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>2</load-on-startup> 
 <init-param> 
 <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/servlet-context.xml</param-value> 
 </init-param> 
</servlet> 

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:

DispatcherServlet will always load its own configuration file using -servlet.xml. It is intended that this file will contain web components such as Controllers, ViewResolvers and LocaleResolvers - but no middle tier components.

The ContextLoaderListener is then used to load the files containing your middle tier and data tier components. Spring will merge all these components into an ApplicationContext making your middle tier components accessible from your web tier components. >Rob Harrop Lead Engineer, dm Server

你的往事 2025-01-08 18:31:11

如果您使用 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.

聚集的泪 2025-01-08 18:31:11

因此每个表的休眠序列都会更新,但我的实体没有插入到数据库中。

即使两个相同的 Spring 上下文没有问题,我也遇到了相同的症状。 forceAjcCompile 选项解决了该问题:

            ...
            <java.version>1.6</java.version>
            <aspectj.version>1.7.0</aspectj.version>
            ...
            <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.6</version>
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjrt</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjtools</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
            </dependencies>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <outxml>true</outxml>
                <showWeaveInfo>false</showWeaveInfo>
                <verbose>false</verbose>
                <complianceLevel>${java.version}</complianceLevel>
                <forceAjcCompile>true</forceAjcCompile>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <Xlint>ignore</Xlint>
            </configuration>
        </plugin>

so the per-table hibernate sequence gets updated but my entity is not inserted into the database.

I was experiencing the same symptom even though there was no problem of two identical Spring contexts. The forceAjcCompile option resolved the issue:

            ...
            <java.version>1.6</java.version>
            <aspectj.version>1.7.0</aspectj.version>
            ...
            <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.6</version>
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjrt</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjtools</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
            </dependencies>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <outxml>true</outxml>
                <showWeaveInfo>false</showWeaveInfo>
                <verbose>false</verbose>
                <complianceLevel>${java.version}</complianceLevel>
                <forceAjcCompile>true</forceAjcCompile>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <Xlint>ignore</Xlint>
            </configuration>
        </plugin>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文