Search code examples
javaspringhibernatejpatransactions

Outer transaction can not retrieve changes from inner transaction if entity already loaded once


  • I have a @Transactional main service loading from repository an entity.
  • Then this service call a sub-service having @Transactional(propagation = Propagation.REQUIRES_NEW) loading the same entity to update one of its properties
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateEntity(Long id) {

        repository.findById(id).get().setName("NEW NAME");
    }
  • Unfortunately, the update done from the sub-service is not visible from the main service, even if I try to reload the entity from repository and no matter which isolation level I choose (READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE).

Here is the code of the main service :

    @Transactional
    public void transactional() {

        MyEntity myEntity1 = repository.findById(1L).get();
        log.info("{} - {}", myEntity1, myEntity1.getName()); // "OLD NAME"

        subService.updateEntity(1L);

        MyEntity myEntity2 = repository.findById(1L).get();
        log.info("{} - {}", myEntity2, myEntity2.getName()); // "OLD NAME" again, and same reference as myEntity1
    }

Nevertheless, If I don't load once the entity in the main service before calling the sub-service, I DO see changes from the inner transaction.

    @Transactional
    public void transactional() {

        subService.updateEntity(1L);

        MyEntity myEntity2 = repository.findById(1L).get();
        log.info("{} - {}", myEntity2, myEntity2.getName()); // "NEW NAME"
    }

I guess what I want to achieve is not a standard way of doing things, but I really want to understand why if an entity is loaded once in an outer transaction, I can not retrieve changes from inner transaction(s).


Solution

  • After edition from the inner transaction, the entity must be explicitly reloaded inside the outer transaction by calling EntityManager#refresh. (Thx to @M.Prokhorov for the clue)

    entityManager.refresh(myEntity1);
    

    As @Kayaman said in comment of my question:

    It's the 1st level cache in action. It won't reload the entity (unless explicitly told to), since you've just loaded it.