开发者

Spring + Eclipselink + JtaTransactionManager = javax.persistence.TransactionRequiredException

I really hope you can help me. I've been looking all over the internet for answers and none of them works.

I use Spring 3 + JTA + EclipseLink but i'm getting a TransactionRequiredException when flushing a transaction. Now i'm very used to just defining my persistence context and injecting the EntityManager and the transaction is handled by the app server.

So here's what I've got.

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

So here's the deal, when I uncomment the transactionManager parts, the program operates as expected, which is I can see the insert statements. However, when using the above code, I get the following stacktrace :

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)

So as you can see, it connects correctly to the database, and it "persists" the data, but never actually execute the insert statement. Then when flushing the EM, it throws the exception.

Your help will be greatly appreciated.

Best Regards.


Ok, so I figured out how to get this working 100%.

First of all, I don't have to define any persistence(context/unit) in web.xml. Next I removed the transactionmanager and the entityManagerFactory beans. Also removed the context:driven line. I also made my "beans" Stateless session beans. I then instantiate it through spring through jndi context lookups. This autowires the entitymanager exactly as i want it. No more worrying about transactions, the app server handles that.

so my final config is :

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" />

bean sample:

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

Then to use the bean, just do a standard spring lookup of the bean. Easy as pie.


In order to use JTA transactions managed by the application server you need to use EntityManagerFactroy created by the application server itself.

I.e. you need to remove your LocalContainerEntityManagerFactoryBean declaration and obtain EntityManagerFactory from the application server via <jee:jndi-lookup>. Also you should configure application server to create EntityManagerFactory - see your application server documentation.

See also:

  • 13.5.1.2 Obtaining an EntityManagerFactory from JNDI


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

set the server type....

hope this one should work..

refer the docs for more details http://docs.oracle.com/middleware/1212/toplink/TLADG/websphere.htm

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜