Objective
To confirm the cause is because of trying to use the Container Managed Transaction in the Web Container, and check if my understanding is correct or not.
(In the example code below, a entity manager (not thread safe) is injected into a servlet instance variable which will cause multi thread issues but it is for testing sake)
Issue
Trying to port the developerWorks example into IBM WAS. Trying to use the Entity Manager em and start a transaction with em.getTransaction().begin() and got the error.
[27/09/15 0:28:33:717 AEST] 00000090 SystemErr
R <openjpa-2.2.3-SNAPSHOT-r422266:1686911 nonfatal user error>
org.apache.openjpa.persistence.InvalidStateException:
You cannot access the EntityTransaction when using managed transactions.
[27/09/15 0:28:33:719 AEST] 00000090 SystemErr R at org.apache.openjpa.persistence.EntityManagerImpl.getTransaction(EntityManagerImpl.java:552)
[27/09/15 0:28:33:719 AEST] 00000090 SystemErr R at org.apache.openjpa.persistence.EntityManagerImpl.getTransaction(EntityManagerImpl.java:102)
[27/09/15 0:28:33:720 AEST] 00000090 SystemErr R at com.ibm.ws.jpa.management.JPAExEmInvocation.getTransaction(JPAExEmInvocation.java:263)
[27/09/15 0:28:33:720 AEST] 00000090 SystemErr R at com.ibm.ws.jpa.management.JPAEntityManager.getTransaction(JPAEntityManager.java:421)
[27/09/15 0:28:33:721 AEST] 00000090 SystemErr R at sample.jpa.servlet.CreateAccount.doPost(CreateAccount.java:35)
[27/09/15 0:28:33:721 AEST] 00000090 SystemErr R at javax.servlet.http.HttpServlet.service(HttpServlet.java:595)
[27/09/15 0:28:33:722 AEST] 00000090 SystemErr R at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
[27/09/15 0:28:33:722 AEST] 00000090 SystemErr R at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1232)
[27/09/15 0:28:33:722 AEST] 00000090 SystemErr R at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:781)
[27/09/15 0:28:33:724 AEST] 00000090 SystemErr R at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:480)
[27/09/15 0:28:33:725 AEST] 00000090 SystemErr R at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:178)
[27/09/15 0:28:33:725 AEST] 00000090 SystemErr R at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1114)
[27/09/15 0:28:33:726 AEST] 00000090 SystemErr R at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:87)
[27/09/15 0:28:33:726 AEST] 00000090 SystemErr R at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:940)
[27/09/15 0:28:33:727 AEST] 00000090 SystemErr R at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1817)
[27/09/15 0:28:33:727 AEST] 00000090 SystemErr R at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:200)
[27/09/15 0:28:33:728 AEST] 00000090 SystemErr R at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:463)
[27/09/15 0:28:33:728 AEST] 00000090 SystemErr R at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:530)
[27/09/15 0:28:33:729 AEST] 00000090 SystemErr R at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:316)
[27/09/15 0:28:33:729 AEST] 00000090 SystemErr R at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:287)
[27/09/15 0:28:33:729 AEST] 00000090 SystemErr R at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
[27/09/15 0:28:33:730 AEST] 00000090 SystemErr R at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
[27/09/15 0:28:33:730 AEST] 00000090 SystemErr R at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:175)
[27/09/15 0:28:33:731 AEST] 00000090 SystemErr R at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
[27/09/15 0:28:33:731 AEST] 00000090 SystemErr R at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
[27/09/15 0:28:33:732 AEST] 00000090 SystemErr R at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
[27/09/15 0:28:33:732 AEST] 00000090 SystemErr R at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
[27/09/15 0:28:33:732 AEST] 00000090 SystemErr R at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
[27/09/15 0:28:33:733 AEST] 00000090 SystemErr R at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
[27/09/15 0:28:33:733 AEST] 00000090 SystemErr R at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1881)
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.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_1_0.xsd">
<persistence-unit name="DB2AccountUnit" transaction-type="JTA">
<jta-data-source>jdbc/DB2</jta-data-source>
<class>sample.jpa.Db2account</class>
<properties>
<property name="openjpa.Log" value="File=C:/opt/openjpa/org.apache.openjpa.log, DefaultLevel=INFO, Runtime=TRACE, Tool=INFO, SQL=TRACE, JDBC=TRACE" />
<property name="openjpa.ConnectionUserName" value="User" />
<property name="openjpa.ConnectionPassword" value="Password" />
</properties>
</persistence-unit>
</persistence>
Code
package sample.jpa.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import javax.transaction.SystemException;
import javax.naming.InitialContext;
import sample.jpa.AccountException;
import sample.jpa.Db2account;
@WebServlet("/CreateAccount")
public class CreateAccount extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
private static final long serialVersionUID = 1L;
@PersistenceContext(unitName="DB2AccountUnit")
EntityManager em;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
synchronized protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
InitialContext context = null;
UserTransaction ut = null;
try {
em.getTransaction().begin(); // <---- Error
long accno = Long.parseLong(request.getParameter("ACCNO"));
Db2account account1 = em.find(Db2account.class, accno);
if (account1 != null) {
throw new AccountException("Error : sample.jpa.servlet.CreateAccount : Account Number already exists:" + accno);
} else {
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");
java.sql.Date dbDate = new java.sql.Date(format.parse(request.getParameter("DOP"), new ParsePosition(0)).getTime());
Db2account account = new Db2account();
account.setOwner(request.getParameter("OWNERNAME"));
account.setAccno(accno);
account.setAccountType(request.getParameter("ACCOUNTTYPE"));
account.setBalance(new BigDecimal(request.getParameter("BALANCE")));
account.setDateOpen(dbDate);
em.persist(account);
em.getTransaction().commit();
response.sendRedirect("Create_Account.jsp");
}
} catch (Exception e) {
e.printStackTrace();
em.getTransaction().rollback();
try{
ut.rollback();
} catch (SystemException se){
se.printStackTrace();
printMessage(se, response.getWriter());
}
}
}
}
Question
(Update: Found the understanding was completely wrong. Put self-answer)
Please advise my understanding below is correct or not.
My understanding is that the error is because the EntityTransaction provided from EntityManager.getTransaction() is to be used as the Container Managed Transaction (CMT) in the EJB Container but not in the Web Container.
The Web Container (I believe in general) does not support CMT, hence the error is caused. The message "You cannot access the EntityTransaction when using managed transactions" means 'You cannot use CMT/EntityTransaction where you need to use Bean Managed Transacdtion and javax.transaction.UserTransaction'.
Environment
IBM WAS 8.5.5.7 for Developers (Apache openjpa-2.2.3-SNAPSHOT-r422266)
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
Windows 7 64 bit on DELL Latitude core i7 2.8GHz 8G memory & SSD HDD
References
Fixed Code
package sample.jpa.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import javax.transaction.SystemException;
import javax.naming.InitialContext;
import sample.jpa.AccountException;
import sample.jpa.Db2account;
@WebServlet("/CreateAccount")
public class CreateAccount extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
private static final long serialVersionUID = 1L;
@PersistenceContext(unitName="DB2AccountUnit")
EntityManager em;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
synchronized protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
InitialContext context = null;
UserTransaction ut = null;
try {
context = new InitialContext();
ut = (UserTransaction)context.lookup("java:comp/UserTransaction");
if(ut == null){
System.out.println("UserTransactin is NULL");
}
// em.getTransaction().begin();
ut.begin();
long accno = Long.parseLong(request.getParameter("ACCNO"));
Db2account account1 = em.find(Db2account.class, accno);
if (account1 != null) {
throw new AccountException("Error : sample.jpa.servlet.CreateAccount : Account Number already exists:" + accno);
} else {
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");
java.sql.Date dbDate = new java.sql.Date(format.parse(request.getParameter("DOP"), new ParsePosition(0)).getTime());
Db2account account = new Db2account();
account.setOwner(request.getParameter("OWNERNAME"));
account.setAccno(accno);
account.setAccountType(request.getParameter("ACCOUNTTYPE"));
account.setBalance(new BigDecimal(request.getParameter("BALANCE")));
account.setDateOpen(dbDate);
em.persist(account);
// em.getTransaction().commit();
ut.commit();
response.sendRedirect("Create_Account.jsp");
}
} catch (Exception e) {
e.printStackTrace();
// em.getTransaction().rollback();
try{
ut.rollback();
} catch (SystemException se){
se.printStackTrace();
}
}
}
}