2

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!

Radu Linu
  • 1,143
  • 13
  • 29
  • 2
    Is your PersitenceContext of type JTA or ResourceLocal?? Your code behaves like it was declared ResourceLocal.... – Carlitos Way Oct 05 '17 at 14:54
  • @CarlitosWay I updated the question with my `persistence.xml` file configuration. Should be as JTA configured. – Radu Linu Oct 05 '17 at 17:18
  • Is the rollback triggered by an exception? As you only specify `catch (Exception ex)`, I wonder: is it a custom exception? If yes, is it annotated [`@ApplicationException`](http://palkonyves.blogspot.fr/2013/04/exceptions-and-transactions-in-ejb.html)? – Al-un Oct 05 '17 at 23:08
  • If your are using wildfy or jboss, remove the properties about flushing from your persistence.xml ans also remove the provider node... and try again... – Carlitos Way Oct 06 '17 at 01:13
  • @Al1 I'm catching all Exceptions and in catch bloc use explicitly `ejbContext.setRollbackOnly();`; this means to rollback the transaction. Also I've tried with a *CustomException* annotated with `@ApplicationException(rollback = true)` but the same result. – Radu Linu Oct 06 '17 at 10:47
  • @CarlitosWay I've removed the configs from `persistence.xml` but is the same result. Any other idea? – Radu Linu Oct 06 '17 at 10:48
  • Researching I've found that *MyApplication* is changing the *MySql* configuration with `SET AUTOCOMMIT = 1` and this mean if I execute a query in mySql that query is automatic **commited**. 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? – Radu Linu Oct 06 '17 at 10:53
  • 1
    No... if you are planning to let the server (EJB) to handle the transaction bounderies, you must avoid configurations like the one you are talking about (set autocommit = 1)... how do you do such kind of configuration?? – Carlitos Way Oct 06 '17 at 14:36
  • @CarlitosWay "*how do you do such kind of configuration??*" Currently I don't know from where comes that configuration. I think that is a default JTA configuration. I found an interesting answer https://stackoverflow.com/a/39719517/4507034 – Radu Linu Oct 06 '17 at 16:05
  • @LinuRadu that is not a default JTA configuration... it seems that is a configuration of your MySQL Database... see [this](https://stackoverflow.com/questions/2950676/difference-between-set-autocommit-1-and-start-transaction-in-mysql-have-i-misse), [this](https://dev.mysql.com/doc/refman/5.7/en/innodb-autocommit-commit-rollback.html) and [this](https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_autocommit) (hope this help) – Carlitos Way Oct 06 '17 at 19:11
  • @CarlitosWay What is the result if you execute this query in your mysql: `SHOW VARIABLES WHERE Variable_name='autocommit';`? If the value is `ON`, means that when you execute `entityManager.flush()` your code should be visible in *mySql* because after the query is executed, commit is automated triggered by mySql. As I understand, if the code is **committed** in *mySql* you cannot rollback that code. The problem is that I set manually in MySql `AUTOCOMMIT = 0` and after *MyApplicationTransaction* that value is back `AUTOCOMMIT = 1`. – Radu Linu Oct 06 '17 at 20:16
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/156139/discussion-between-carlitos-way-and-linu-radu). – Carlitos Way Oct 07 '17 at 00:37

0 Answers0