Spring org.apache.openjpa.persistence.InvalidStateException: you cannot access the EntityTransaction when using managed transactions

StackOverflow https://stackoverflow.com/questions/23644216

Вопрос

I am attempting a simple container managed transaction using spring, jpa 2.0 and a PersistenceContext annotated EntityManager.

Below is my app-context.xml (spring config):

<beans ...>

    <context:annotation-config />

    <context:component-scan base-package="com.example.test.config" />
    <context:component-scan base-package="com.example.test.controllers" />
    <context:component-scan base-package="com.example.test.services" />

    <jee:jndi-lookup id="myDS" jndi-name="jdbc/myDS" expected-type="javax.sql.DataSource" />

    <bean id="myEMF" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="testPU"/>
        <property name="packagesToScan" value="com.example.test.model"/>
        <property name="jtaDataSource" ref="saturnDS"/>
        <property name="mappingResources" value="META-INF/orm.xml" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter" />
        </property>
    </bean>

    <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="myEMF" />
        <property name="dataSource" ref="myDS" />
    </bean>

    <tx:annotation-driven transaction-manager="txManager"/>

</beans>

I have a service in com.example.test.services called MyServiceImpl:

@Repository("myService")
@Transactional
public class MyServiceImpl implements MyService{

    @PersistenceContext(unitName = "testPU")
    @Qualifier("myEMF")
    private EntityManager em;

    @Override
    public String getMessage() {
        return "Hello, World!";
    }

    @Override
    public Customer getFirstCustomer() {
        CustomerId id = new CustomerId();
        id.setId(new BigInteger("1"));
        id.setStartVersion(1);
        return em.find(Customer.class, id); // it uses a composite key
    }
}

I am getting the following error when i attempt to call the getFirstCustomer() method using a bean injected into an mvc controller (not shown for brevity's sake):

UPDATE: here is the full stacktrace:

    [14/05/14 11:01:20:812 EST] 0000008f webapp        E com.ibm.ws.webcontainer.webapp.WebApp logServletError SRVE0293E: [Servlet Error]-[DispatcherServlet]: org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is <openjpa-2.2.2-SNAPSHOT-r422266:1462076 nonfatal user error> org.apache.openjpa.persistence.InvalidStateException: You cannot access the EntityTransaction when using managed transactions.
    at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:430)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:420)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:257)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy525.getMessage(Unknown Source)
    at com.example.test.controllers.IndexController.showIndex(IndexController.java:23)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:88)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
    at java.lang.reflect.Method.invoke(Method.java:613)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:575)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1227)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:776)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:458)
    at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:178)
    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1032)
    at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3761)
    at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:304)
    at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:976)
    at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1662)
    at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:200)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:459)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:526)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:312)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:283)
    at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
    at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
    at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:175)
    at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
    at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
    at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
    at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
    at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
    at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
    at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1862)
Caused by: <openjpa-2.2.2-SNAPSHOT-r422266:1462076 nonfatal user error> org.apache.openjpa.persistence.InvalidStateException: You cannot access the EntityTransaction when using managed transactions.
    at org.apache.openjpa.persistence.EntityManagerImpl.getTransaction(EntityManagerImpl.java:552)
    at org.apache.openjpa.persistence.EntityManagerImpl.getTransaction(EntityManagerImpl.java:102)
    at org.springframework.orm.jpa.DefaultJpaDialect.beginTransaction(DefaultJpaDialect.java:67)
    at org.springframework.orm.jpa.vendor.OpenJpaDialect.beginTransaction(OpenJpaDialect.java:50)
    at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:380)
    ... 49 more

I am using WebSphere v8.5.5.0 and Spring 4.0.4

Forgive me if this is fundamental knowledge i should know, I would just like the injected EntityManager to be valid for my transactional purposes.

UPDATE: Since I am using websphere, I need a transactionManager obtained from the Container. I have swapped out my transactionManager reference for the following:

<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.transaction.jta.WebSphereUowTransactionManager" />

However now the app is complaining that the Customer class has not been Enhanced when it is definitely in the "packagesToScan property of the EMF.

UPDATE: This is my entity class: (note I am using lombok which generates boilerplate for me.

package com.example.test.model;
import ...;
@Entity
@Getter
@Setter
@Table(name = Rep.TABLE_NAME)
@IdClass(CustomerId.class)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode
public class Customer implements Serializable {

    public static final String TABLE_NAME = "Customer";
    public static final String ID_COLUMN = "CUSTOMERID";
    public static final String START_VERSION_COLUMN = "STARTVERSION";
    /* etc */

    @Id
    @Column(name = ID_COLUMN, nullable = false, insertable = true, updatable = true, precision = 0)
    private BigInteger id;

    @Id
    @Column(name = START_VERSION_COLUMN, nullable = false, insertable = true, updatable = true)
    private int startVersion;

    /* etc ad. nauseum */

}
Это было полезно?

Решение

I have reached a solution and there are a few things I have learned whilst researching an answer.

First of all, Because I am using Websphere, The transaction manager is supplied by the container already. This can be declared as a bean in my config like so:

<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.transaction.jta.WebSphereUowTransactionManager" />

transactionManager is the default name that the <tx:annotation-driven /> tag looks for to initialize it's transaction-manager (otherwise specified by the transaction-manager attribute.

Secondly, The spring container does not automatically transform entity classes at runtime, To specify this requirement means adding a LoadTimeWeaver to the LocalContainerEntityManagerFactoryBean declaration:

<bean id="myEMF" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="loadTimeWeaver">
        <!-- Spring provides a websphere compatible load time weaver -->
        <bean class="org.springframework.instrument.classloading.websphere.WebSphereLoadTimeWeaver" />
    </property>
    ....
</bean>

Now that both of these elements are in place, the function gracefully returns the desired Customer object from the method call :)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top