После почти 10 часов поиска и проб разных вещей я не мог понять, что является главной причиной моей проблемы.Так что, может быть, кто-то может помочь мне здесь.Я учу Spring + JPA.У меня есть проект EAR (в Eclipse), состоящий из двух проектов: JPA и Servlets.Этот EAR развертывается на сервере приложений Glassfish.
Проект JPA: Бины, службы и DAO.
Проект сервлета: Только один простой HttpRequestHandlerServlet, вызов службы из JPA.
Проблема: На стороне сервлета получение данных из dao (через службу) работает нормально.Хранение данных вызывает TransactionRequiredException
.
Проект JPA
Dao:
@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>
Проект сервлета
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>
Сводка
В тестовом сервлете вызов 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)
Основные примечания:
- Проблема вызвана
em.flush()
. - Получение данных из JPA / db работает хорошо из сервлетов.
- Из контейнераМодульные тесты в проекте JPA работают хорошо (тоже em.flush).
- Инициализация контекстов пружин кажется хорошей в соответствии с журналами пружин.ServiceContext создан и WebApplicationContext впоследствии создается с его parrent.
Я попытался найти проблему где-то в моей иерархической инициализации контекста, поместив ее в проект Servlet, я также попробовал только одно определение bean-компонента вApplicationContext.xml проекта сервлета.Ничего из этого не работает, так что проблема, вероятно, будет где-то еще.
Действительно спасибо за любые комментарии, С уважением Z.