【问题标题】:Spring + Eclipselink + JtaTransactionManager = javax.persistence.TransactionRequiredExceptionSpring + Eclipselink + JtaTransactionManager = javax.persistence.TransactionRequiredException
【发布时间】:2011-08-03 15:47:30
【问题描述】:

我真的希望你能帮助我。我一直在互联网上寻找答案,但没有一个有效。

我使用 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>

spring-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;
    }
}

所以这是交易,当我取消注释事务管理器部分时,程序按预期运行,即我可以看到插入语句。但是,当使用上面的代码时,我得到以下堆栈跟踪:

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 时,它会抛出异常。

我们将不胜感激。

最好的问候。

【问题讨论】:

    标签: spring eclipselink jta entitymanager


    【解决方案1】:

    好的,所以我想出了如何让它 100% 工作。

    首先,我不必在 web.xml 中定义任何持久性(上下文/单元)。接下来我删除了 transactionmanager 和 entityManagerFactory bean。还删除了 context:driven 行。 我还制作了我的“bean”无状态会话 bean。然后我通过 jndi 上下文查找通过 spring 实例化它。这完全按照我的意愿自动装配实体管理器。无需再担心事务,应用服务器会处理。

    所以我的最终配置是:

    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();
        }
    }
    

    然后要使用 bean,只需对 bean 进行标准的 spring 查找。很简单。

    【讨论】:

      【解决方案2】:

      为了使用由应用服务器管理的 JTA 事务,您需要使用由应用服务器自己创建的EntityManagerFactroy

      即您需要删除您的LocalContainerEntityManagerFactoryBean 声明并通过&lt;jee:jndi-lookup&gt; 从应用程序服务器获取EntityManagerFactory。此外,您应该配置应用程序服务器以创建 EntityManagerFactory - 请参阅您的应用程序服务器文档。

      另请参阅:

      【讨论】:

      • @axtavt 但如何在不使用 J2EE 容器(即使用 BTM 或 JOTM 等第三方事务管理器)的情况下运行相同的示例?
      【解决方案3】:

      property name="eclipselink.target-server" value="WebSphere_7"

      设置服务器类型....

      希望这个能工作..

      请参阅文档以获取更多详细信息 http://docs.oracle.com/middleware/1212/toplink/TLADG/websphere.htm

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-07-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多