Spring + Eclipselink + JtaTransactionManager = javax.persistence.TransactionRequiredException
Я действительно надеюсь, что вы можете мне помочь. Я искал ответы в Интернете, и ни один из них не работает.
Я использую Spring 3 + JTA + EclipseLink, но я получаю TransactionRequiredException при очистке транзакции. Теперь я очень привык просто определять свой постоянный контекст и вводить EntityManager, а транзакция обрабатывается сервером приложений.
Итак, вот что у меня есть.
persistence.xml
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="CartouchanPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:app/jdbc/CartouchanDS</jta-data-source>
<class>com.cartouchan.locator.database.models.Authority</class>
<class>com.cartouchan.locator.database.models.AuthorityPK</class>
<class>com.cartouchan.locator.database.models.User</class>
<class>com.cartouchan.locator.database.models.UserPK</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="eclipselink.ddl-generation" value="none"/>
<property name="eclipselink.target-database" value="MySQL"/>
<property name="eclipselink.jdbc.native-sql" value="true"/>
<property name="eclipselink.jdbc.cache-statements" value="true"/>
</properties>
</persistence-unit>
</persistence>
весна-config.xml
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<jee:jndi-lookup jndi-name="java:app/jdbc/CartouchanDS" id="CartouchanDS" />
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="autodetectUserTransaction" value="true" />
<property name="autodetectTransactionManager" value="true" />
<property name="transactionManagerName" value="java:appserver/TransactionManager"/>
</bean>
<context:annotation-config />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="CartouchanPU" />
<property name="persistenceUnitManager">
<bean class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"/>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="true" />
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect" />
</property>
</bean>
CreateAccount.class
import java.text.MessageFormat;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class CreateAccount implements Controller {
private static final Logger logger = Logger.getLogger(CreateAccount.class);
// @Autowired
// private JtaTransactionManager transactionManager;
@PersistenceContext
private EntityManager entityManager;
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
logger.info(MessageFormat.format("Called handle request", ""));
String username = ServletRequestUtils.getRequiredStringParameter(request, "username");
logger.info(MessageFormat.format("username {0}", username));
String password = ServletRequestUtils.getRequiredStringParameter(request, "password");
logger.info(MessageFormat.format("password {0}", password));
String passwordConfirm = ServletRequestUtils.getRequiredStringParameter(request, "passwordConfirm");
logger.info(MessageFormat.format("passwordConfirm {0}", passwordConfirm));
if (!password.equals(passwordConfirm)) {
throw new ServletRequestBindingException("Passwords don't match");
}
//transactionManager.getUserTransaction().begin();
User user = new User();
//try {
UserPK userPK = new UserPK();
userPK.setUsername(username);
user.setId(userPK);
user.setPassword(passwordConfirm);
user.setEnabled((byte) 1);
logger.info(MessageFormat.format("persist the user {0}", username));
entityManager.persist(user);
entityManager.flush();
// logger.info(MessageFormat.format("Before Refresh user {0}", username));
// entityManager.refresh(user);
// transactionManager.getUserTransaction().commit();
// } catch (Exception e) {
// logger.error(MessageFormat.format("Got an exception {0}", e.getMessage()), e);
// transactionManager.getUserTransaction().rollback();
// }
// transactionManager.getUserTransaction().begin();
// AuthorityPK authorityPK = new AuthorityPK();
// //try {
// logger.info(MessageFormat.format("Refreshed user {0} = {1}", username, user.getId()));
//
// authorityPK.setUserId(user.getId().getId());
// authorityPK.setAuthority(com.cartouchan.locator.models.Authority.ROLE_USER.toString());
// Authority authority = new Authority();
// authority.setId(authorityPK);
//
// logger.info(MessageFormat.format("Save the authority {0}", com.cartouchan.locator.models.Authority.ROLE_USER.toString()));
// entityManager.persist(authority);
// transactionManager.getUserTransaction().commit();
// } catch (Exception e) {
// logger.error(MessageFormat.format("Got an exception {0}", e.getMessage()), e);
// transactionManager.getUserTransaction().rollback();
// }
logger.info(MessageFormat.format("Go to /index.zul", ""));
ModelAndView modelAndView = new ModelAndView("index");
logger.info(MessageFormat.format("Return ", ""));
return modelAndView;
}
}
Итак, вот в чем дело, когда я раскомментирую части actionManager, программа работает, как и ожидалось, то есть я вижу оператор вставки. Однако при использовании приведенного выше кода я получаю следующую трассировку стека:
INFO: Starting ZK 5.0.7.1 CE (build: 2011051910)
INFO: Parsing jndi:/server/Cartouchan/WEB-INF/zk.xml
INFO: WEB0671: Loading application [Cartouchan-Web] at [/Cartouchan]
INFO: Cartouchan-Web was successfully deployed in 1,537 milliseconds.
INFO: 2011-08-04 01:09:52 CreateAccount [INFO] Called handle request
INFO: 2011-08-04 01:09:52 CreateAccount [INFO] username blah
INFO: 2011-08-04 01:09:52 CreateAccount [INFO] password test
INFO: 2011-08-04 01:09:52 CreateAccount [INFO] passwordConfirm test
INFO: 2011-08-04 01:09:52 CreateAccount [INFO] persist the user blah
INFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver.
INFO: EclipseLink, version: Eclipse Persistence Services - 2.2.0.v20110202-r8913
CONFIG: connecting(DatabaseLogin(
platform=>MySQLPlatform
user name=> ""
connector=>JNDIConnector datasource name=>null
))
CONFIG: Connected: jdbc:mysql://localhost:3306/Cartouchan
User: root@localhost
Database: MySQL Version: 5.1.51
Driver: MySQL-AB JDBC Driver Version: mysql-connector-java-5.1.11 ( Revision: ${svn.Revision} )
CONFIG: connecting(DatabaseLogin(
platform=>MySQLPlatform
user name=> ""
connector=>JNDIConnector datasource name=>null
))
CONFIG: Connected: jdbc:mysql://localhost:3306/Cartouchan
User: root@localhost
Database: MySQL Version: 5.1.51
Driver: MySQL-AB JDBC Driver Version: mysql-connector-java-5.1.11 ( Revision: ${svn.Revision} )
INFO: file:/Applications/NetBeans/glassfish-3.1/glassfish/domains/domain1/eclipseApps/Cartouchan-Web/WEB-INF/classes/_CartouchanPU login successful
WARNING: StandardWrapperValve[cartouchan]: PWC1406: Servlet.service() for servlet cartouchan 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:1666)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:744)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy151.flush(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy151.flush(Unknown Source)
at com.cartouchan.locator.controllers.CreateAccount.handleRequest(CreateAccount.java:56)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:755)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1534)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:368)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:78)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:112)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:177)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:187)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:169)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:326)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:227)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:170)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:822)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:719)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1013)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:680)
Итак, как вы можете видеть, он правильно подключается к базе данных и "сохраняет" данные, но фактически никогда не выполняет оператор вставки. Затем при сбросе EM, это исключение.
Ваша помощь будет принята с благодарностью.
С уважением.
3 ответа
Хорошо, я понял, как это работает на 100%.
Прежде всего, мне не нужно определять постоянство (context/unit) в web.xml. Затем я удалил менеджер транзакций и компоненты entityManagerFactory. Также удален контекст: ведомая строка. Я также сделал мои "бобы" сессионные бобы без состояния. Затем я создаю его экземпляр с помощью весенних поисков в jndi. Это автоматически связывает EntityManager точно так, как я хочу. Больше не нужно беспокоиться о транзакциях, сервер приложений справится с этим.
так что мой последний конфиг:
spring-config.xml:
<jee:jndi-lookup jndi-name="java:global/Cartouchan-Web/CategoryController" id="categoryController"/>
<jee:jndi-lookup jndi-name="java:global/Cartouchan-Web/UserController" id="userController"/>
<bean id="applicationContextProvider" class="com.cartouchan.locator.beans.CustomApplicationContext"></bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
образец бобов:
import java.text.MessageFormat;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.log4j.Logger;
@Stateless
public class CategoryController {
private static final Logger logger = Logger.getLogger(CategoryController.class);
@PersistenceContext
private EntityManager entityManager;
public CategoryController() {
// TODO Auto-generated constructor stub
}
public boolean createCategory(final String name) {
boolean result = false;
try {
com.cartouchan.locator.database.models.Category category = new com.cartouchan.locator.database.models.Category();
category.setName(name);
entityManager.persist(category);
entityManager.flush();
result = true;
} catch (Exception ex) {
logger.error(MessageFormat.format("Could not create the category {0}", name), ex);
}
return result;
}
public boolean updateCategory(final int id, final String name) {
boolean result = false;
try {
com.cartouchan.locator.database.models.Category category = getCategory(id);
category.setName(name);
entityManager.merge(category);
entityManager.flush();
result = true;
} catch (Exception ex) {
logger.error(MessageFormat.format("Could not update for the category {0} -{1}", id, name), ex);
}
return result;
}
public boolean deleteCategory(final int id) {
boolean result = false;
try {
com.cartouchan.locator.database.models.Category category = getCategory(id);
entityManager.remove(entityManager.merge(category));
entityManager.flush();
result = true;
} catch (Exception ex) {
logger.error(MessageFormat.format("Could not delete for the category {0}", id), ex);
}
return result;
}
public com.cartouchan.locator.database.models.Category getCategory(final int id) {
return (com.cartouchan.locator.database.models.Category) entityManager.createQuery("select p from Category p where p.id=:id").setParameter("id", id).getSingleResult();
}
public List<com.cartouchan.locator.database.models.Category> getAllCategories() {
return (List<com.cartouchan.locator.database.models.Category>) entityManager.createQuery("select p from Category p").getResultList();
}
}
Затем, чтобы использовать боб, просто выполните стандартный весенний поиск боба. Проще простого.
Свойство name="eclipselink.target-server" value="WebSphere_7"
установить тип сервера....
надеюсь, что это должно работать..
обратитесь к документации для более подробной информации http://docs.oracle.com/middleware/1212/toplink/TLADG/websphere.htm
Для использования транзакций JTA, управляемых сервером приложений, необходимо использовать EntityManagerFactroy
созданный самим сервером приложений.
Т.е. вам нужно удалить свой LocalContainerEntityManagerFactoryBean
декларация и получение EntityManagerFactory
с сервера приложений через <jee:jndi-lookup>
, Также вам необходимо настроить сервер приложений для создания EntityManagerFactory
см. документацию вашего сервера приложений.
Смотрите также: