How Stateless EJB rollback JPA transactions - jpa

Having for eg:
#Stateless
public class EntityRepositry{
#Inject
EntityManager em;
public void create(Entity e){
// op1 success
// op2 failed
}
}
As Stateless EJB are by default transactional, I would understand how the transaction if a system exception (like OptimisticLockedException) is thrown, will be rollbacked? How em.getTransaction().rollback will be called implicitly?
Thanks in advance.

EntityManager are injected with #PeristenceContext annotation (or may you have a CDI producer?)
If the persistence unit is declared to use JTA transactions
<persistence-unit name="myname" transaction-type="JTA">
then the EJB transaction is bound to the JPA transaction and viceversa.
JPA Exceptions rollback the whole transation but remember that any RuntimeException will rollback a transaction, checked exception doesn't.
So if you use JTA transaction management you don't have to rollback manually transactions, just throw or catch the right exception (catching RuntimeException don't prevent the transaction to be rolled back but allow you to manage it).

Related

Transaction Error JTA DATASOURCE JPA CDI

data-source with JBoss EAP in my project.
For some reason when i try to persist an object i get the error below.
JBAS011469: Transaction is required to perform this operation (either
use a transaction or extended persistence context):
javax.faces.FacesException: #{back.salvar}:
javax.persistence.TransactionRequiredException: JBAS011469:
Transaction is required to perform this operation (either use a
transaction or extended persistence context)
There is #Transactional method but this method launch the error.
Anyone?
#Stateless
#Named
public class BaseDao implements Serializable
{
private static final long serialVersionUID = -8993128837557701804L;
#PersistenceContext
protected EntityManager manager;
#Transactional
public void persist(Object object)
{
manager.persist(object);
}
}
PS: All objects are injected with CDI, the manager is injected with the object class org.jboss.as.jpa.container.TransactionScopedEntityManager
As your CDI bean is an EJB stateless session bean, you don't have to use #Transactional annotation here since EJB have Container Managed Transaction (CMT) by default.
#Transactional is useful to manage transaction transaction on a CDI managed bean (i.e. POJO).

JTA controlled transactions in JBoss AS7 using EclipseLink, Transaction is required

Environment
Application server: JBoss AS7 (7.1.1 Final)
JPA implementation: EclipseLink (2.4.1)
OS: Windows 7 DB: PostgreSQL 8.4
Update 2, solved
The problem was that i instantiated the AccountService class instead of injecting it using #EJB. After fixing that EntityManager was inected correctly in the service and a transaction was available when doing em.persist(account);
Update
I made a minimal project that shows my problems. Posted to Github:
https://github.com/gotling/jboss-eclipselink-problem
I have two problems that are probably related and due to me not understanding the use of EJB's correct.
I can not get EnityManager to be injected in AccountService.java in persistance JAR, resulting in NullPointerException.
If sending EntityManager in constructor to AccountService no tranasaction is found when doing em.persist.
Project structure
EJB
lib/persistanceunit.jar
web-service.war
Problem
I'm trying to get JBoss to manage transactions in my Java EE service. Problem is that EclipseLink does not seem to pick up the transaction managed by JBoss when trying to persist an entity.
I have followed the guide https://community.jboss.org/wiki/HowToUseEclipseLinkWithAS7 (Alternative 1 and Alternative 2 Step 4) on how to configure JBoss with EclipseLink.
Setup
WAR
Entity manager is injected like this in web-service.war:
#WebService(....)
public class NotificationConsumerImpl implements NotificationConsumer {
#PersistenceContext(unitName="foo")
EntityManager em;
public void notify(Notify notify) {
AccountService accountService = new AccountService(em);
accountService.create(notify);
}
}
There is actually a controller class between the class above and the service class, where transformation of the Account object is done, removed it to shorten code.
Persistance Unit
Entity is created like this
AccountService.java in persistanceunit.jar
#Stateless
public class AccountService {
private EntityManager em;
public AccountService(EntityManager em) {
this.em = em;
}
public void create(Account account) {
em.persist(account);
}
}
Stack trace
When calling a WS that should persist the Account entity I get an exception on em.persist(account);
...
Caused by: javax.persistence.TransactionRequiredException: JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
at org.jboss.as.jpa.container.AbstractEntityManager.transactionIsRequired(AbstractEntityManager.java:692) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.jpa.container.AbstractEntityManager.persist(AbstractEntityManager.java:562) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
at se.magos.service.AccountService.create(AccountService.java:50) [persistenceunit-0.0.1-SNAPSHOT.jar:]
Questions
I've enabled Trace logging. Should not id.au.ringerc.as7.eclipselinkpersistence be visible in the log?
Is it somehow possible to get the EntityManager injected inside the service class inside the persistanceunit.jar?
In which JBoss / EclipseLink version should this wor out of the box?
You should annotate the bean with #TransactionManagement(TransactionManagementType.CONTAINER) and the create method with #TransactionAttribute(TransactionAttributeType.REQUIRED).
The first annotation is required in order to let the application server know that transactions are managed by the container, the latter to let the method start a transaction, if there is no current one, as soon as it is invoked.
The problem was that AccountService class was instantiated instead of injected using #EJB annotation. After fixing that EntityManager was injected correctly in the service and a transaction was available when doing em.persist(account);
Before
#WebService(....)
public class NotificationConsumerImpl implements NotificationConsumer {
#PersistenceContext(unitName="foo")
EntityManager em;
public void notify(Notify notify) {
AccountService accountService = new AccountService(em);
accountService.create(notify);
}
}
After
#WebService(....)
public class NotificationConsumerImpl implements NotificationConsumer {
#PersistenceContext(unitName="foo")
EntityManager em;
#EJB
AccountService accountService;
public void notify(Notify notify) {
accountService.create(notify);
}
}

Glassfish: JTA/JPA transaction not rolling back

I am running Glassfish 3.1.1 with an Oracle database and have run into an issue with transactions not rolling back, but only on one specific environment so far. The same application works as expected on other machines. However, two separate Glassfish domains on the same machine are impacted.
Within the affected environment, I have similar results with both a container-managed transactions (CMT) inside an EJB that throws a RuntimeException, and a bean-managed transaction (BMT) with UserTransaction#rollback().
In both cases, the underlying issue appears to be that the JDBC connection is somehow still set with autoCommit = true even though there is a JTA transaction in progress.
My EJB/CMT test looks like this:
#Named
#Stateless
public class TransactionTest {
#PersistenceContext
EntityManager entityManager;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void rollbackTest() {
Foo foo = new Foo();
entityManager.persist(foo);
entityManager.flush();
throw new RuntimeException("should be rolled back");
}
}
and my BMT/UserTransaction test is like this:
public void rollbackUtxTest() throws Exception {
utx.begin();
Foo foo = new Foo();
entityManager.persist(foo);
entityManager.flush();
utx.rollback();
}
When I call either method, the INSERT INTO FOO is committed, even though the transactions were rolled back.
What am I missing - perhaps I don't have my connection pool / datasource is not set up right?
I'm using OracleConnectionPoolDataSource as the datasource class name. Is there something I need to do to ensure my database connections participate in JTA transactions?
UPDATE 1 I originally thought this was an issue with OracleConnectionPoolDataSource but it turned out it was not correlated. The same exact pool configuration works on one environment but not the other.
UPDATE 2 Clarified that this is not specifically an EJB/CMT issue, but a general JTA issue.
UPDATE 3 added info about JDBC autocommit. Confirmed that persistence.xml is correct.
It looks like this may be an issue with domain.xml, possibly a Glassfish bug.
In persistence.xml, I have
<jta-data-source>jdbc/TEST</jta-data-source>.
In domain.xml, I have
<jdbc-resource pool-name="TEST_POOL" description="" jndi-name="jdbc/TEST"></jdbc-resource>
But no corresponding <resource-ref ref="jdbc/TEST"> - either missing or misspelled. (I believe I ended up in that state by creating the JNDI datasource through the UI, realizing the name is wrong, then fixing the JNDI name in domain.xml jdbc-resource by hand but not fixing it in resource-ref.
In this case, my injected EntityManager still works but is not participating in JTA transactions. If I fix domain.xml, it works as expected.
You didn't wrap your Exception in an EJBException.
See http://docs.oracle.com/javaee/6/tutorial/doc/bnbpj.html

TomEE 4 JPA issue

I am trying out simple JPA example on TomEE 4.0.0 and I am not able to get PersistenceContextType.EXTENDED working
If I make my session bean Stateless and leave PersistenceContextType then it works fine
#PersistenceContext(unitName = "xxx" )
private EntityManager entityManager;
If I keep my session bean as Stateless and then try to use this
#PersistenceContext(unitName = "xxx", type = PersistenceContextType.EXTENDED))
private EntityManager entityManager;
it gives me an error while deploying, which is perfectly fine and in line with expectation.
However now when I make my bean as #Stateful, then also it gives me an error
Managed ejbs are not capable of using EntityManagers with EXTENTED persistence. Convert your bean to a Stateful ejb or update the "java:comp/env/com.testwebservice.TestJPAService/entityManager" PersistenceContext reference to PersistenceContextType.TRANSACTION.
Can some one please help, I am really confused for this
#Stateful EXTENDED persistence contexts are tested in numerous ways in the TomEE build and also in the Java EE TCK.
Likely this is something else completely. We do our best to warn you when you make obvious mistakes as you note with the incorrect combination of #Stateless with PersistenceContextType.EXTENDED
Looking at the JNDI name which contains com.testwebservice.TestJPAService and given the fact it was #Stateless before it was changed to #Stateful, my guess is that this bean is also an #WebService which is illegal. #Stateful beans cannot be #WebService beans. Without a proper check to prevent this mistake, my guess is that the bean is actually being deployed twice; once as a #Stateful bean and once as an pojo #WebService. The pojo web service is the one causing the error.
In case that is the error, I've filed a JIRA for us to explicitly check that condition.

Glassfish doesn't bring up EntityManager if DAO is not Stateless

I have an EAR application with an EJB module, that contains one persistence unit and many EJBs (as service and DAO layer).
#Stateless
public class BranchDAO {
#PersistenceContext
private EntityManager entityManager;
}
But DAOs as Stateless beans are not recommended. So I create this annotation using CDI:
#Dependent
#Stereotype
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface DAO {
}
After my DAO is changed to not use #Stateless:
#DAO
public class BranchDAO {
#PersistenceContext
private EntityManager entityManager;
}
But the Glassfish doesn't bring up the entity manager when the application starts. And when I call the DAO, the entity manager is in an illegal state.
java.lang.IllegalStateException: Unable to retrieve EntityManagerFactory for unitName null
This error only occurs in Glassfish 3, but not in JBoss AS 6. Using JBoss AS 6 I can see the Hibernate logs in startup (but I don't see them with Glassfish).
As a temporary solution I created an Stateless bean with the content below. It's not beautiful solution, but works fine in Glassfish.
#Stateless
#Startup
public class AutoStartEntityManager {
#PersistenceContext
private EntityManager entityManager;
}
So, how I can force Glassfish to bring up EntityManager when I'm not using #Stateless in my DAO?
Try specifying explicitly the unitName:
#PersistenceContext(unitName="yourJPAUnitName")
private EntityManager manager;
(A sidenote - are you sure you need the DAO in dependent scope? Shouldn't it be singleton?)