Spring,JPA,glassfish,EAR,TransactionRequiredException

时间:2011-12-15 11:16:48

标签: spring jpa glassfish ear

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

JPA项目: Bean,Services和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. 从servlet获取数据来自JPA / db。
  3. 容器外的JPA项目中的单元测试运行良好(em.flush)。
  4. 根据春季记录,春季背景的初始化似乎很好。创建ServiceContext,然后使用其parrent创建WebApplicationContext。
  5. 我试图通过放置在Servlet项目中初始化我的层次化上下文中的某个地方找到问题,我还在servlet项目的ApplicationContext.xml中只尝试了一个bean定义。这些都不起作用,所以问题可能在其他地方。

    非常感谢任何评论,关心Z。

2 个答案:

答案 0 :(得分:1)

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

其次,虽然我还没有直接使用EclipseLink JPA实现,但从这个例外情况来看,您已尝试启动全局事务,但尚未配置全局(JTA)事务管理器实现。 / p>

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

  • 在services.xml中,您已配置了本地管理的事务管理器(org.springframework.orm.jpa.JpaTransactionManager),
  • 在persistence.xml中,您已配置JPA提供程序以期望给定数据源的GLOBAL事务管理(通过<jta-data-source>jdbc/test</jta-data-source>

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

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

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

答案 1 :(得分:1)

我换了:

  • glassfish - &gt; JBoss的,
  • eclipselink - &gt;冬眠。

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