Save #Entity using #EntityManager not working - java

Trying to persist an entity is not working but retrieving a list is.
Below is my Bean: (a)
#Stateless
public class UsersClass {
#PersistenceContext(unitName = "unit")
private EntityManager em;
public UsersClass () {}
public void create(Users entity) {
em.persist(entity);
}
}
persistence.xml as below:
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="unit" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/ds</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
</properties>
</persistence-unit>
</persistence>
Beans have to be #Stateless. Above, setup executes fine - no exception or anything but nothing gets saved in DB also.
Tried whats mentioned here. Not sure if I did it correctly or not but was getting exception.
I also tried whats mentioned here and modified as below:(b)
#Stateless
public class UsersClass {
#PersistenceContext(unitName = "unit")
private EntityManager em;
#Resource
private SessionContext sessionContext;
public UsersClass () {}
public void create(Users entity) {
UserTransaction userTxn = sessionContext.getUserTransaction();
try {
userTxn.begin();
getEntityManager().persist(entity);
userTxn.commit();
} catch(Throwable e){
e.printStackTrace();
try {
userTxn.rollback();
} catch (IllegalStateException | SecurityException | SystemException e1) {
e1.printStackTrace();
}
}
}
}
but got the below stack trace -
Caused by: java.lang.IllegalStateException: Only session beans with bean-managed transactions can obtain UserTransaction
at com.sun.ejb.containers.EJBContainerTransactionManager.getUserTransaction(EJBContainerTransactionManager.java:566)
at com.sun.ejb.containers.BaseContainer.getUserTransaction(BaseContainer.java:995)
at com.sun.ejb.containers.AbstractSessionContextImpl.getUserTransaction(AbstractSessionContextImpl.java:120)
So as per my readings, I thought adding #TransactionManagement(TransactionManagementType.BEAN) to my class should help. Indeed, the exception is gone but nothing get persisted in the db.
Have also tried - entitymanager.getTransaction().begin() and commit() but there I get the below stack-trace
Caused by: java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
at org.hibernate.internal.AbstractSharedSessionContract.getTransaction(AbstractSharedSessionContract.java:360)
at org.hibernate.internal.AbstractSessionImpl.getTransaction(AbstractSessionImpl.java:23)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.getTransaction(EntityManagerWrapper.java:806)
It would really help me if someone can point out the missing piece of code.
Update 1 -
I have tried the below set of changes also with (b)
userTxn.begin();
getEntityManager().joinTransaction();
getEntityManager().persist(entity);
userTxn.commit();
Am getting below stack-trace -
org.hibernate.resource.transaction.backend.jta.internal.JtaPlatformInaccessibleException: Unable to access TransactionManager or UserTransaction to make physical transaction delegate
at org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl.makePhysicalTransactionDelegate(JtaTransactionCoordinatorImpl.java:229)
at org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl.getTransactionDriverControl(JtaTransactionCoordinatorImpl.java:203)
at org.hibernate.engine.transaction.internal.TransactionImpl.<init>(TransactionImpl.java:37)
at org.hibernate.internal.AbstractSharedSessionContract.accessTransaction(AbstractSharedSessionContract.java:372)
at org.hibernate.internal.AbstractSharedSessionContract.markForRollbackOnly(AbstractSharedSessionContract.java:342)
at org.hibernate.internal.ExceptionConverterImpl.handlePersistenceException(ExceptionConverterImpl.java:271)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:148)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155)
at org.hibernate.internal.SessionImpl.joinTransaction(SessionImpl.java:3736)
at org.hibernate.internal.SessionImpl.joinTransaction(SessionImpl.java:3718)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.joinTransaction(EntityManagerWrapper.java:990)

Container Managed Transaction
This seems to be OK, your create method in your Users stateless bean starts the transaction automatically. You entityManager takes part in the transaction and the changes should be persisted to the Database. What was the exception in this case?
Container Managed Transaction and try to start a JTA transaction
Your create method starts a transaction automatically, you tried to start another JTA transaction in the code and you got a 'IllegalStateException'. If you want to take control of the transaction in the code, change the configuration to Bean Managed Transaction.
Bean Managed Transaction
You are controlling the Transaction in the code. The code doesn't throw any exception but the changes are not being persisted. This is because the EntityManager is not joining the transaction. If you have an EntityManager created before the start of the JTA transaction, you need to call the method joinTransaction() to make the EntityManager to join the transaction:
userTxn.begin();
EntityManager em = getEntityManager();
em.joinTransaction();
em.persist(entity);
userTxn.commit();

Can't you get the Transaction from the EntityManager
em.getTransaction().begin ();
see https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html#getTransaction--

You are using JTA transaction. You dont need to manage transaction in this case. It is container managed. I think you should use #Transactional annotation on create function or if you want to manage transaction by yourself then you need to use transaction type LOCAL and you need to get entitymanager instance from entitymanager factory in this case.

Related

Cannot use an EntityTransaction while using JTA. Using non-jta

I'm trying to do a CRUD and my persistence.xml have non-JTA-data-source but when I try to do something like create, update or delete I receive a message that says: Cannot use an EntityTransaction while using JTA
An example of muy code:
#Transactional
public void destroy(T entity) throws Exception
{
EntityManager em = getEntityManager();
try
{
em.getTransaction().begin();
em.remove(em.merge(entity));
em.getTransaction().commit();
}
catch(Exception e)
{
em.getTransaction().rollback();
throw new Exception(e);
}
finally
{
if (em.isOpen())
{
em.close();
}
}
}
My persistence:
<persistence-unit name="namePU" transaction-type="RESOURCE_LOCAL">
<non-jta-data-source>database</non-jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
</persistence-unit>
Based on the Transactional annotation, it seems you are using Spring's transaction management. In that case, there is no point in trying to manually control the transaction via em.getTransaction(). Also, I don't know how you get the EntityManager, but that may interfere with Spring's transaction management as well.
Either stick to the Spring way of declarative transaction management (IMHO better idea), or remove Transactional and EntityManager injection and manage the PU and transactions yourself.

Transaction is not accessible when using JTA with JPA-compliant transaction access enabled

I have a Transaction Manager injected with #PersistenceContext context annotation. Every time I'm trying to start the transaction with em.getTransaction().begin I got an exception with the error message
Transaction is not accessible when using JTA with JPA-compliant transaction access enabled
I know that I should inject UserTransaction or use #Transactional annotation but I want to know the reason for such behavior.
I think you should inject a container managed transaction.
Something like:
#Resource
private UserTransaction transaction;
public method() {
try {
transaction.begin();
...do some persistence...
transaction.commit();
} catch (Exception e) {
transaction.rollback();
}
}
OR
if you don't need such control you can use #Transaction annotation on your method.
Hope it helps.
I had the very same issue but problem lied elsewhere...
So the stack: I was using Wildfly server , postgresql, and JPA
At first, my persistence.xml was configured to use RESOURCE_LOCAL transactions e.g.
<persistence-unit name="unit" transaction-type="RESOURCE_LOCAL">
and I had a problem that even when the method was marked #Transactional it was not doing any rollbacks when error occured, yet saving worked fine.
So then I decided to use transaction-type JTA instead of RESOURCE_LOCAL so that the container manages the transactions.
When I changed my persistence.xml to this, it was still not working
<persistence-unit name="unit" transaction-type="JTA">
<jta-data-source>java:jboss/datasources/unit</jta-data-source>
and was throwing the very error that is in the title of this question.
My problem was, how I was creating the EntityManager, this is how it was defined
#Produces
#PersistenceContext
private static EntityManager em = Persistence.createEntityManagerFactory(UNIT_NAME).createEntityManager()
The solution? I had to remove the annotation #PersistenceContext
P.s. for JTA transactions do not forget to tell wildfly about the datasource for example via CLI like this
data-source add --jndi-name=java:jboss/datasources/unit --name=MyDb --connection-url=jdbc:postgresql://localhost:5432/postgres --driver-name=postgresql --user-name=username --password=password

Managing Multiple Database Connections

I've been struggling with this problem for days,
Here is the scenario:
I have several databases, one for each of my customers, all of them with the same
structure(same tables and columns), so my application needs to decide at runtime with which one it needs to connect. I'm using JPA2, EclipseLink and EJB3.
My first attempt was to implement a custom EntityManager with all the logic to performs the operations on the right database, then I configured this EntityManager as an Stateless EBJ in order to make it possible to inject it with the #EBJ annotation (as described at this link: http://www.hostettler.net/blog/2012/11/20/multi-tenancy/). I coundn't make it work because it was throwing an exception when trying to inject the EntityManager.
So I decided to try something else, I've created EntityManagerFactory and I passed the
JTA_DATASOURCE to it(after decide at runtime which one to use), so it could connect to the
right database.
Here is the code:
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
public class TestEntDAO {
private EntityManager em;
private EntityManagerFactory emf;
#PostConstruct
public void init() {
em = getEntityManager();
}
public EntityManager getEntityManager() {
Map props = new HashMap();
props.put(PersistenceUnitProperties.TRANSACTION_TYPE, "JTA");
props.put(PersistenceUnitProperties.JTA_DATASOURCE, dataSourceName());
emf = Persistence.createEntityManagerFactory("testePU", props);
em = emf.createEntityManager();
return em;
}
public String dataSourceName(){
if(someCondition){
return "db1";
}else{
return "db2";
}
}
}
This worked perfectly, the only problem is that the transaction is not managed by the
container, so I had to explicitly mark the transaction's boundaries(call begin() and
commit()). I could just use the #PersistenceContext annotation to make it work, but then I
wouldn't have the EntityManagerFactory to pass the datasource.
Does anyone know of a way to use the Container-Managed Transactions(CMT) and still be able
to pass the datasource?
Maybe try to define 3 Data sources and 3 Persistence units.
<persistence-unit name="PU1">
<jta-data-source>jdbc/DS1</jta-data-source>
...
</persistence-unit>
<persistence-unit name="PU2">
<jta-data-source>jdbc/DS2</jta-data-source>
...
</persistence-unit>
<persistence-unit name="PU3">
<jta-data-source>jdbc/DS3</jta-data-source>
...
</persistence-unit>
And inject Entity manager from whatever Persistence unit you want.
#PersistenceContext(unitName = "PU2")
EntityManager em;
This should work, although I didn't test it.

Why different persistence units with separated data sources query the same data source?

I'm developing a webapp which needs access to two different database servers (H2 and Oracle).
The container is an Apache Tomee 1.5.1 and I'm using the Java EE stack with libraries provided in it (JSF, JPA, CDI, EJB, etc.).
I'm trying to use two entity managers inside an XA transaction to extract data from the Oracle database and persist it in the H2 after transforming it, BUT all the queries are executed against the H2 database no matter the entity manager I use. Any help?
EDIT: I found that if I try to access the entity managers in inverse order, they behavior is the same but accessing to Oracle. I.e.: the entity managers stay with the first database accessed.
The EJB where this happens (calling service.getFoo() from JSF):
#Named
#Stateless
public class Service {
#Inject
#OracleDatabase
private EntityManager emOracle;
#Inject
#H2Database
private EntityManager emH2;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public List<Foo> getFoo() {
TypedQuery<Foo> q = emH2.createQuery(
"SELECT x FROM Foo f", Foo.class);
List<Foo> l = q.getResultList();
if (l == null || l.isEmpty()) {
update();
}
return q.getResultList();
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void update() {
// FAIL: This query executes against H2 with Oracle entity manager!
List<Object[]> l = emOracle.createNativeQuery("SELECT * FROM bar ").getResultList();
//more stuff...
}
}
The resource producer (CDI) for the entity managers (where #H2Database and #OracleDatabase are qualifiers):
public class Resources {
#Produces
#PersistenceContext(unitName = "OraclePU")
#OracleDatabase
private EntityManager emOracle;
#Produces
#PersistenceContext(unitName = "H2PU")
#H2Database
private EntityManager emH2;
}
My peristence.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<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="H2PU"
transaction-type="JTA">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<jta-data-source>H2DS</jta-data-source>
<class>my.app.h2.Foo</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
</persistence-unit>
<persistence-unit name="OraclePU" transaction-type="JTA">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<jta-data-source>OracleDS</jta-data-source>
<class>my.app.oracle.Bar</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
</persistence-unit>
</persistence>
And finally, the data sources inside tomee.xml (there aren't any other data sources configured inside this file):
<Resource id="OracleDS" type="javax.sql.DataSource">
jdbcDriver = oracle.jdbc.xa.client.OracleXADataSource
jdbcUrl = jdbc:oracle:thin:#server:port:instance
jtaManaged = true
password = abcde
userName = user
</Resource>
<Resource id="H2DS" type="javax.sql.DataSource">
jdbcDriver=org.h2.jdbcx.JdbcDataSource
jdbcUrl=jdbc:h2:h2/db;AUTO_SERVER=TRUE
jtaManaged = true
password = edcba
userName = user
</Resource>
Container Managed Persistence Contexts
When using container-managed persistence contexts (as you are via #PersistenceContext annotations), the JPA spec specifies that only ONE persistence context may be associated with a JTA transaction.
The persistence context is created by the Java EE container. Despite appearances of the code (#PersistenceContext annotations seem to suggest that PC is injected directly into your EntityManager instance variables), the persistence context is actually stored as a reference WITHIN THE JTA TRANSACTION. Each time an EntityManager operation occurs it does not refer to it's own internal persistence context. Instead it does a special operation because it is container managed - it always looks up the persistence context within the JTA Transaction and uses that. This is called JTA persistence context propagation.
Some Quotes from the JPA spec:
When a container-managed entity manager is used, the lifecycle of the
persistence context is always managed automatically, transparently to
the application, and the persistence context is propagated with the
JTA transaction.
Container-managed Transaction-scoped Persistence Context
...
A new persistence context begins when the container-managed entity manager
is invoked[76] in the scope of an active JTA transaction, and there is
no current persistence context already associated with the JTA
transaction. The persistence context is created and then associated
with the JTA transaction.
Container-managed Extended Persistence Context
...
A container-managed extended persistence context can only be initiated within the scope
of a stateful session bean. It exists from the point at which the stateful session bean
that declares a dependency on an entity manager of type PersistenceContextType.EXTENDED
is created, and is said to be bound to the stateful session bean. The dependency on the
extended persistence context is declared by means of the PersistenceContext annotation or persistence-context-ref deployment descriptor element.
The persistence context is closed by the container when the #Remove method of the stateful session bean completes (or the stateful session bean instance is otherwise destroyed).
Requirements for Persistence Context Propagation
... If a component is called and there is no JTA transaction ..., the persistence context is not propagated.
• Invocation of an entity manager defined with PersistenceContext-
Type.TRANSACTION will result in use of a new persistence context.
• Invocation of an entity manager defined with PersistenceContext-
Type.EXTENDED will result in the use of the existing extended persistence context
bound to that component.
... If a component is called and the JTA transaction is propagated into that component:
• If the component is a stateful session bean to which an extended persistence context has been bound and there is a different persistence context bound to the JTA transaction, an EJBException is thrown by the container.
• Otherwise, if there is a persistence context bound to the JTA transaction, that persistence context is propagated and used.
So that's your problem.
The obvious $64 question: WHY does the spec ask for this???
Well, it's because it's a deliberate trade-off that brings powerful EntityManager magic to EJBs.
Using JTA transactions to propagate a single persistence context has a limitation: transactions cannot straddle multiple persistence contexts, so can't straddle multiple databases.
However, it also has a tremendous advantage: any entityManager declared in EJBs can automatically share the same persistence context and hence can operate on the same set of JPA entities and partake in the same transaction. You can have a chain of EJBs calling other EJBs of any complexity and they all behave sensibly and consistently against the JPA entity data. And they also do not need the complexity of consistently intializing/sharing entity manager references across method invocations - the EntityManagers can be declared privately in each method. The implementation logic can be very simple.
The Answer To Your Problem: Use Application-Managed Persistence Contexts (via application-managed EntityManagers)
Declare your entityManager via one of these approaches:
// "Java EE style" declaration of EM
#PersistenceUnit(unitName="H2PU")
EntityManagerFactory emfH2;
EntityManager emH2 = emfH2.createEntityManager();
OR
// "JSE style" declaration of EM
EntityManagerFactory emfH2 = javax.persistence.Persistence.createEntityManagerFactory("H2PU");
EntityManager emH2 = emfH2.createEntityManager();
and the same for emfOracle & emOracle.
You must call em.close() when you are finished with each EM - prefereably via a final { } clause or via a Java 7 try-with-resources statement.
Application-managed EMs still partake in (i.e. synchronise with) JTA transactions. Any number of application-managed EMs can partake in a single JTA transaction - but none of these will ever have their persistence context associated with or propagated to any container managed EM.
If the EntityManager is created outside the context of a JTA transaction (before the transaction commenced), then you must ask it explicity to join the JTA transaction:
// must be run from within Java EE code scope that already has a JTA
// transaction active:
em.joinTransaction();
Or even simpler, if the EntityManager is created inside the context of a JTA transaction, then the application-managed EntityManager automatically joins the JTA transaction implicity - no joinTransaction() needed.
So Application-managed EMs can have a JTA transaction that straddles multiple databases. Of course, you can alway run a local resource JDBC transaction independent of JTA:
EntityTransaction tx = em.getTransaction();
tx.begin();
// ....
tx.commit();
EDIT: EXTRA DETAILS for Transaction Management with Application-Managed Entity Managers
WARNING: the code samples below are for educational use - I've typed them off the top of my head to help explain my points & haven't had time to compile/debug/test.
The default #TransactionManagement parameter for EJBs is TransactionManagement.CONTAINER and the default #TransactionAttribute parameter for EJB methods is TransactionAttribute.REQUIRED.
There are four permutations for transaction management:
A) EJB with CONTAINER managed JTA transactions
This is the preferred Java EE approach.
EJB class #TransactionManagement annotation:
must set to TransactionManagement.CONTAINER explicitly or omit it to implicitly use the default value.
EJB method #TransactionAttribute annotation:
must set to TransactionAttribute.REQUIRED explicitly or omit it to implicity use the default value. (Note: if you had a different business scenario, you could use TransactionAttribute.MANDATORY or TransactionAttribute.REQUIRES_NEW if their semantics matched your needs.)
Application-managed entity managers:
they must be created via Persistence.createEntityManagerFactory("unitName") and emf.createEntityManager(), as described above.
Join the EntityManagers with the JTA transaction:
Create the EntityManagers WITHIN a transactional EJB method and they will automatically join the JTA transaction. OR if EntityManagers are created beforehand, call em.joinTransaction() within a transaction EJB method.
Call EntityManager.close() when you are finished using them.
That should be all that's required.
Basic Examples - just use more EntityManagers for transaction across multiple DBs:
#Stateless
public class EmployeeServiceBean implements EmployeeService {
// Transactional method
public void createEmployee() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService");
EntityManager em = emf.createEntityManager();
Employee emp = ...; // set some data
// No need for manual join - em created in active tx context, automatic join:
// em.joinTransaction();
em.persist(emp);
// other data & em operations ...
// call other EJBs to partake in same transaction ...
em.close(); // Note: em can be closed before JTA tx committed.
// Persistence Context will still exist & be propagated
// within JTA tx. Another EM instance could be declared and it
// would propagate & associate the persistence context to it.
// Some time later when tx is committed [at end of this
// method], Data will still be flushed and committed and
// Persistence Context removed .
emf.close();
}
}
#Stateful
public class EmployeeServiceBean implements EmployeeService {
// Because bean is stateful, can store as instance vars and use in multiple methods
private EntityManagerFactory emf;
private EntityManager em;
#PostConstruct // automatically called when EJB constructed and session starts
public void init() {
emf = Persistence.createEntityManagerFactory("EmployeeService");
em = emf.createEntityManager();
}
// Transactional method
public void createEmployee() {
Employee emp = ...; // set some data
em.joinTransaction(); // em created before JTA tx - manual join
em.persist(emp);
}
// Transactional method
public void updateEmployee() {
Employee emp = em.find(...); // load the employee
// don't do join if both methods called in same session - can only call once:
// em.joinTransaction(); // em created before JTA tx - manual join
emp.set(...); // change some data
// no persist call - automatically flushed with commit
}
#Remove // automatically called when EJB session ends
public void cleanup() {
em.close();
emf.close();
}
// ...
}
B) EJB with BEAN managed JTA transactions
Use #TransactionManagement.BEAN.
Inject the JTA UserTransaction interface, so the bean can directly mark JTA transactions.
Manually mark/synchronize the transaction via UserTransaction.begin()/commit()/rollback().
Ensure the EntityManager joins the JTA transaction - either create the EM in an active JTA transaction context OR call em.joinTransaction().
Examples:
#TransactionManagement(TransactionManagement.BEAN)
#Stateless
public class EmployeeServiceBean implements EmployeeService {
// inject the JTA transaction interface
#Resource UserTransaction jtaTx;
public void createEmployee() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService");
EntityManager em = emf.createEntityManager();
try {
jtaTx.begin();
try {
em.joinTransaction();
Employee emp = ...; // set some data
em.persist(emp);
// other data & em operations ...
// call other EJBs to partake in same transaction ...
} finally {
jtaTx.commit();
}
} catch (Exception e) {
// handle exceptions from UserTransaction methods
// ...
}
Employee emp = ...; // set some data
// No need for manual join - em created in active tx context, automatic join:
// em.joinTransaction();
em.persist(emp);
em.close(); // Note: em can be closed before JTA tx committed.
// Persistence Context will still exist inside JTA tx.
// Data will still be flushed and committed and Persistence
// Context removed some time later when tx is committed.
emf.close();
}
}
C) POJO/Non-EJB with hand-coded (bean managed) resource local transactions (not JTA)
Simply use the JPA EntityTransaction interface for tx demarcation (obtained via em.getTransaction()).
Example:
public class ProjectServlet extends HttpServlet {
#EJB ProjectService bean;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// ...
try {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
bean.assignEmployeeToProject(projectId, empId);
bean.updateProjectStatistics();
} finally {
tx.commit();
}
} catch (Exception e) {
// handle exceptions from EntityTransaction methods
// ...
}
// ...
}
}
D) POJO/Non-EJB with hand-coded (POJO-managed) JTA transactions
This assumes the POJO/component is running in some container that has JTA support.
If in a Java EE container, can use Java EE resource injection of JTA UserTransaction interface.
(Alternatively, can explicitly lookup a handle to the JTA interface and do demarcation on it, then call em.getTransaction().joinTransaction() - see JTA spec.)
Example:
public class ProjectServlet extends HttpServlet {
#Resource UserTransaction tx;
#EJB ProjectService bean;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// ...
try {
tx.begin();
try {
bean.assignEmployeeToProject(projectId, empId);
bean.updateProjectStatistics();
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU");
EntityManager em = emf.createEntityManager();
// Should be able to avoid explicit call to join transaction.
// Should automatically join because EM created in active tx context.
// em.joinTransaction();
// em operations on data here
em.close();
emf.close();
} finally {
tx.commit();
}
} catch (Exception e) {
// handle exceptions from UserTransaction methods
// ...
}
// ...
}
}
Try to create a Query not a native query first, returning a list of Bars.
Also try to comment the H2 injection in your EJB. If it works, then you know that is a CDI conflict problem.

A JTA EntityManager cannot use getTransaction()

How can I use the following code in my non-ejb application. The code works.
#Override
public void saveItems(Collection<T> items) {
synchronized (em) {
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
for (T item : items) {
saveItem_((Class<T>) null, item);
}
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
}
}
In a new application I'm using EJB3 + JSF and would like to re-use the library containing the code above. My peristence unit for the new application looks like this:
<persistence-unit name="myApp" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>MySQLConnection</jta-data-source>
</persistence-unit>
My new application throw an exception when it hits this line:
EntityTransaction tx = em.getTransaction();
the exception is:
A JTA EntityManager cannot use getTransaction()
Which is clear enough. The question is how would I convert my code to have the transactions managed by the container. Presumably my bean methods need to be annotated appropriately... The question is how?
EntityTransaction is used with entity manager of type resource local. If you want to use JTA, then have to use UserTransaction interface.
From Documentation : EntityTransaction - Interface used to control transactions on resource-local entity managers. The EntityManager.getTransaction() method returns the EntityTransaction interface.
Edit: Added pseudo code.
#Resource
private SessionContext sessionContext;
void execute(){
UserTransaction userTxn = sessionContext.getUserTransaction();
try{
userTxn.begin();
/**
* do-something
*/
userTxn.commit();
} catch(Throwable e){
userTxn.rollback(); //-- Include this in try-catch
}
}
In the simplest case - it just works. If you have your EntityManager injected into EJB and use no special annotations, the transaction will open in the first EJB method entered (this means that if EjbA calls EjbB and that in turn calls EjbC, only one transaction will be used across all the EJB methods). If you want to modify how transactions are controlled, look up #Transaction.
The simplest way to do a rollback is to throw an exception marked with #ApplicationException(rollback=true)
I may be wrong, but judging from your code you should read up on the difference between EXTENDED and NORMAL EntityManager. It looks like you are using an extended em in a very awkward way (moving the loop out of transaction would help you get rid of finally).
Small edit: if you try to use UserTransaction, as the other post suggests, you will get an error, because a standard EntityManager (that you are probably using) uses the so called CMT (Container Managed Transactions). Don't touch it, unless you understand the three basic opositions (if you want, I can elaborate, but frankly, you will NOT need it):
container managed EntityManager versus application managed EntityManager,
container managed transactions versus application managed transactions,
NORMAL EntityManager and EXTENDED EntityManager.
just to summarize the code that works for me on Jboss EAP6 and Hibernate 4.2.18.Final.
May save time for someone.
persistence.xml
<persistence 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"
version="2.0">
<persistence-unit name="myApp" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/MySQLConnection</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
<!--
<property name="hibernate.show_sql" value="true" />
-->
</properties>
</persistence-unit>
java
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.transaction.UserTransaction;
public class MyClass {
#PersistenceContext(unitName = "myApp")
protected EntityManager em;
#Resource
UserTransaction utx;
public void execute(..) throws Exception {
try {
utx.begin();
em.remove(..);
em.merge(..);
em.persist(..);
utx.commit();
} catch (Exception ex) {
try {
utx.rollback();
} catch (Exception re) {
throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
}
throw ex;
}
}
}
pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
<scope>provided</scope>
</dependency>
links:
Application-Managed Entity Managers https://docs.oracle.com/cd/E19798-01/821-1841/bnbra/index.html
How does the UserTransaction and the EntityManager interact?
"May save time for someone."
It sure saved me time! I wish I'd found your solution days ago. I've been struggling with how to handle bean-managed transactions in the context of a JTA persistence unit. Most of our use is only one JPA DML call within a bean method. The problem was that after performing a single DML operation, a subsequent call (within the same bean method) to a stored procedure would fail, complaining about not being able to start another transaction within the running transaction. The documentation is thorough but ponderous.
This was key: #Resource UserTransaction utx;
Thank you!

Categories

Resources