Search code examples
javatransactionsjta

JPA transaction stores insertions inmediatly in DataBase


When I save a new entity inside the transactional (TransactionAttributeType.REQUIRED) method createEntities the entities are stored inmediatly in the DB before the transaction is finished. I expected that the transaction was finished and the changes propagated to DB when the createEntities method finished but if I debug and pause the execution in the syso lines I can see the changes in DB in an external app (Toad for example).

Am I wrong in my guessing or am I configuring methods wrong?

My code is like this below:

@Stateless
public class MyClass {
    @Inject
    private MyService myService;
    
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void aMethod() {
        // don't want a transaction because this method does a lot of calculations
        // and lasts a lot of time resulting in transaction timeout otherway
        
        createEntities();
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void createEntities() {
        myService.createEntity(new MyEntity(1, "111"));
        System.out.println("Paused execution, checked DB and saw the entity was already inserted");
        myService.createEntity(new MyEntity(2, "222"));
        System.out.println("Paused execution, checked DB and saw the entity was already inserted");
    }
}

@Stateless
public class MyService {
    @PersistenceContext
    private EntityManager em;
    
    public void createEntity(MyEntity entity) {
        em.merge(entity);
    }
}

Solution

  • The @TransactionAttribute works only if the Method is called from another Bean.
    If you call aMethod() from some other Bean, the call will be intercepted to suspend an eventually active Transcation.
    Then createEntities() is then called with no Transaction active, but this call will not be intercepted, because it is called from inside the MyClass-Bean.
    Therefore no Transaction will be started.
    The createEntity()-Method is not annotated and therefore has TransactionAttribute.Required active.
    And because this Method isn't called from the same Bean and no Transaction is active, the Container will start a new one. This Transaction gets commited at the end of the Method.

    More about Container-Manged Transcations: https://docs.oracle.com/javaee/6/tutorial/doc/bncij.html