【问题标题】:Spring, JPA, glassfish, EAR, TransactionRequiredExceptionSpring,JPA,glassfish,EAR,TransactionRequiredException
【发布时间】:2012-01-09 21:01:42
【问题描述】:

经过近 10 个小时的搜索和尝试不同的事情,我无法弄清楚,我的问题的主要原因是什么。所以,也许有人可以在这里帮助我。我正在学习 Spring + JPA。我的 EAR 项目(在 Eclipse 中)由两个项目组成:JPA 和 Servlets。这个 EAR 正在被部署在 Glassfish 应用服务器上。

JPA 项目: Bean、服务和 DAO。

Servlet 项目:只有一个简单的 HttpRequestHandlerServlet,从 JPA 调用服务。

问题: 在 servlet 方面,从 dao(通过服务)获取数据工作正常。存储数据正在提高TransactionRequiredException


JPA 项目

道:

@PersistenceContext
EntityManager em;

@Transactional
public void persist(Employee entity) {
        em.persist(entity);
        em.flush();
    }
}

服务:

@Autowired
private EmployeeDao dao;

public Employee store(Employee in) {
    dao.persist(in);
    return in;
}

services.xml:

<tx:annotation-driven transaction-manager="transactionManager" />
<context:annotation-config />
<context:load-time-weaver />
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/test" />

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

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

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

<bean id="employeeDao" class="... EmployeeDaoImpl" />
<bean id="employeeService" class="... EmployeeServiceImpl">
    <property name="employeeDao" ref="employeeDao" />
</bean>

beanRefContext.xml:

<bean id="serviceContext"
    class="org.springframework.context.support.ClassPathXmlApplicationContext">
    <constructor-arg>
        <list>
            <value>classpath:services.xml</value>
        </list>
    </constructor-arg>
</bean>

persistence.xml:

<persistence-unit name="testJPA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/test</jta-data-source> 
    <class>... entity.Employee</class>
    <properties>
        <property name="eclipselink.logging.level" value="FINE"/>
    </properties> 
</persistence-unit>

Servlet 项目

web.xml:

<context-param>
    <param-name>parentContextKey</param-name>
    <param-value>serviceContext</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
    <servlet-name>test</servlet-name>
    <servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>test</servlet-name>
    <url-pattern>/Test</url-pattern>
</servlet-mapping>

applicationContext.xml:

<bean id="test" class="... TestServlet">
    <property name="employeeService" ref="employeeService" />
</bean>

总结

在测试 servlet 中,调用 employeeService.store( ... ) 会引发异常:

    WARNING: StandardWrapperValve[test]: PWC1406: Servlet.service() for servlet testt threw exception
javax.persistence.TransactionRequiredException: 
Exception Description: No externally managed transaction is currently active for this thread
    at org.eclipse.persistence.internal.jpa.transaction.JTATransactionWrapper.throwCheckTransactionFailedException(JTATransactionWrapper.java:86)
    at org.eclipse.persistence.internal.jpa.transaction.JTATransactionWrapper.checkForTransaction(JTATransactionWrapper.java:46)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.checkForTransaction(EntityManagerImpl.java:1776)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:780)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)

主要说明:

  1. em.flush() 抛出了问题。
  2. 从 JPA/db 获取数据在 servlet 中运行良好。
  3. JPA 项目中的容器外单元测试运行良好(em.flush 也是)。
  4. 根据 spring 日志,spring 上下文的初始化似乎很好。创建 ServiceContext,然后创建 WebApplicationContext 及其父对象。

我试图通过放置在 Servlet 项目中来在我的分层上下文初始化中的某处找到问题,我还尝试了在 servlet 项目的 ApplicationContext.xml 中只定义一个 bean。这些都不起作用,所以问题可能出在其他地方。

非常感谢任何 cmets,问候 Z。

【问题讨论】:

    标签: spring jpa glassfish ear


    【解决方案1】:

    首先,考虑到直接在 DAO 级别标记 @Transactional 在设计方面被认为有些不明智 - 通常,事务跨越服务层,因此建议仅在服务层上进行事务分界。

    其次,虽然我没有直接使用 EclipseLink JPA 实现,但从这个异常来看,您已经尝试启动全局事务,但您还没有配置全局 (JTA) 事务管理器实现。

    您的配置似乎也暗示了这一点:

    • 在 services.xml 中,您已配置本地管理的事务管理器 (org.springframework.orm.jpa.JpaTransactionManager),
    • 在 persistence.xml 中,您已将 JPA 提供程序配置为期望对给定数据源进行 GLOBAL 事务管理(通过 &lt;jta-data-source&gt;jdbc/test&lt;/jta-data-source&gt;

    如果您需要使用本地事务(95% 的情况都是这种情况),您必须使用以下内容配置 JPA 提供程序以进行本地事务:

        <persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
              <non-jta-data-source>jdbc/test</non-jta-data-source>
        </persistence-unit>
    

    如果您确实需要全局事务,那么您需要将不同的事务管理器实现注入 Spring 上下文。关于如何配置此场景的更详细说明取决于实际实现本身 - 我想到的两个免费提供是 AtomikosBitronix。它们都很好地与 Spring 集成,并且有很好的文档记录。

    【讨论】:

    • 感谢您的回复。我很抱歉迟到了(因为我的假期)。由于我是这方面的新手,我有点困惑。如果我使用RESOURCE_LOCAL,我会得到“只有事务类型为 JTA 的持久性单元可以用作容器管理实体管理器”。错误。我也尝试关注这个example,这在我的环境中看起来是最好的方法。没有任何帮助:-(。
    【解决方案2】:

    我换了:

    • glassfish -> jboss,
    • eclipselink -> 休眠。

    我的配置工作没有任何更改。

    【讨论】:

    • 所以 glassfish 是鲤鱼,ecliplink 也是鲤鱼?
    猜你喜欢
    • 1970-01-01
    • 2016-11-12
    • 2015-08-15
    • 1970-01-01
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    • 2020-01-28
    • 2019-02-02
    相关资源
    最近更新 更多