0

I'm having some flaky issues with transactional hibernate. As shown in the example below the entity is persisted with persist(), I retrieve the entity with find() and return the Id from the method. But when the Id is used later to retrieve the entity again, it sometimes (1/2000) cannot find the entity again.

  • I thought when leaving the first @Transactional create method that hibernate would commit?
  • Could it be that hibernate has yet to be able to commit before the getById() is ran?
  • Could it be that @TransactionManagement(TransactionManagementType.CONTAINER) is affecting how and when hibernate commits?
@TransactionManagement(TransactionManagementType.CONTAINER)
public class MDB implements MessageListener {

    @Inject
    private MyService service;

    @Override
    public void onMessage(final Message message) {
        Id id = service.create(message);
        ...
        // Will not find entity on next method call.
        MyEntity  myEntity = service.getById(id);
    }

}

public class MyServiceImpl implements MyService {
   
   @Override
   @Transactional(Transactional.TxType.REQUIRED)
   public Id create(Message message) {
       MyEntity myEntity = new MyEntity();
       Id id = new Id(message);
       myEntity.setId(id);

       entityManager().perisist(myEntity);

       MyEntity myEntityFromEm = entityManager().find(MyEntity.class, id);
       return myEntityFromEm.getId();
   }
   
   @Override
   @Transactional(Transactional.TxType.REQUIRED)
   public MyEntity getById(Id id) {
       return entityManager().find(MyEntity.class, id); 
       // Exception here - Cannot find entity with this id.
   }

}

Have omitted to recreate how the class gets its injected EntityManager, and how the MessageListener is configered. In the real program there is multiple lines in-between create() and getById().

I expected that hibernate did a commit on the persisted entity when leaving the method. I have tried to log the EntityManager HashCode, suspecting that different "sessions" caused the issues. I have tried to manually flush(), but since I cannot reproduce the issue in pilot/test, it is very hard to test.

canEE
  • 3
  • 2
  • Calling methods on the same class will [skip the proxy](https://stackoverflow.com/q/34197964/2541560) that handles annotations like `@Transactional`, so neither `create` or `getById` will start a transaction. That and suitable timing with the default behaviour is likely the problem. – Kayaman Aug 08 '23 at 14:58
  • @Kayaman I had no idea that calling methods in same class would affect anything. Then my example isn't really realistic. I have updated my code example. Would having the ```create()``` and ```getById()``` methods in a service class change anything? – canEE Aug 09 '23 at 07:32
  • Yes it would change something. Just like the linked question explains. I don't know what your real code looks like, but I'd probably use `merge()` since your code looks weird. Why would you do a save/load in a convoluted way like that? – Kayaman Aug 09 '23 at 09:34
  • @Kayaman Why we first ```persist()``` then do a ```find()``` on the same entity to return the Id, I do not know, it is before my time. My guess, trying to verify that it is *inserted*. The application receive messages from queue, we insert a row in the database and continue working on the message. Later on in the progress we want to update the status. We do not keep the entity class after it is inserted, we do a ```find()``` when we want to do changes to it. But you think changing ```persist()``` to ```merge()``` could solve the issue? What about doing ```flush()``` after ```persist()```? – canEE Aug 09 '23 at 11:34

0 Answers0