In a method within an EJB I want to rollback the transaction and revert all data in case one of updates is failing.
The idea is that when the update for objectB is failing I want to revert also the update for objectA.
In exception handling block I've marked the transaction with ejbContext.setRollbackOnly();
but the state of objectA is not rolled back.
Did tests with update
operation and is the same situation.
Here is a short reproduction of what I want to do:
@Stateless
public class Bean1 {
@PersistenceContext
protected EntityManager em;
@Resource
protected EJBContext ejbContext;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Override
public void deleteObjects(A objectA, B objectB) {
try {
// try to remove the ObjectA
if (!em.contains(objectA)) {
objectA= em.merge(objectA);
}
em.remove(objectA);
// try to remove the ObjectB
if (!em.contains(objectB)) {
objectB= em.merge(objectB);
}
em.remove(objectB);
/*
At this step the objectA is removed and the state is flushed to DB
and erased from DB but; when is trying to remove the objectB
an ConstraintViolationException is thrown and the object
is not removed.
*/
em.flush();
} catch (Exception ex) {
// here I mark the transaction for rollback, but the objectA is
// definitively removed from DB
ejbContext.setRollbackOnly();
throw ex;
}
}
}
I have the following Hibernate configuration in the persistence.xml file:
<persistence-unit name="testProject-persistence-unit" transaction-type="JTA">
<description>Persistence unit for testProject</description>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="false" />
<property name="hibernate.flushMode" value="COMMIT"/>
<property name="org.hibernate.flushMode" value="COMMIT"/>
</properties>
<jta-data-source>java:jboss/datasources/testProject</jta-data-source>
</persistence-unit>
Hibernate libraries:
Hibernate: 4.3.10.Final
Important
Also if I remove em.flush()
the objectA is not rolled back. The explication is that when the method is executed (completed) transaction will be committed, initially objectA is automatically flushed and when trying to flush objectB an exception is thrown.
[Update_1]
I've realized that the transaction is rolledback but the changes propagated to DB are not reverted. Also for this piece of code the rollback is not reverting the written value in DB.
... // the same code as before
try {
objectA.setField1("new value");
em.merge(objectA);
//after this step the changes are in DB
em.flush();
// mark to rollback the transaction
// after this line the transaction is relledback and closed
// but the changes stay with the new values in DB
ejbContext.setRollbackOnly();
} catch (Exception ex) {...
[Update_2]
Researching I've found that MyApplication is changing the MySql configuration(AUTOCOMMIT
) with SET AUTOCOMMIT = 1
and this mean if I execute a query in mySql that query is automatic committed. With entityManager.flush()
all queries are executed in mySql and my assumption is that MyApplication should set AUTOCOMMIT = 1
every time is starting a new transaction. Am I right? Is there a configuration for hibernate designed to this behavior?
Any suggestion is welcome!