0

I have several repositories extending BaseRepository as follows:

public abstract class IsoRepository<T extends Serializable> {
    @PersistenceContext
    protected EntityManager entityManager;

    public void persist(T obj) {
        entityManager.persist(obj);
    }
}

@Stateless
public class T1Repository extends BaseRepository<T1> {
    // methods depending on repository
}

@Stateless
public class T2Repository extends BaseRepository<T2> {
    public Optional<T2> findByOrderId(String id) {
        return entityManager.createNamedQuery(/* ... */, T2.class)
            .setParameter("id", id).getResultList().stream().findFirst();
    }
}

// and others

EJB bean contains method reponsible for saving transaction:

@Stateless
public class TransactionService {
    @EJB
    private T2Repository t2Repository;

    public void saveTransaction() {
        // Here occurs logic that saves new entities to database via repositories injected with EJB annotation
        // and also as the last operation update is performed:
        T2 t2 = t2Repository.findById(id);
        t2.setProperty(someProperty);
        t2Repository.persist(t2);
    }
}

The problem is that all insert queries are saved in the database, but not this one poor update. I found out that I need to call entityManager.flush() explicitly, as it seems to solve the issue, but I do not really understand why is that happening. I've always thought that after transaction is committed all data is flushed automatically anyways. Do I have do change something in the configuration?

Fuv
  • 922
  • 2
  • 12
  • 25
  • flush() is called automatically at the end of a transaction. you call t2Repository inside one transaction and you don't have auto flush. "I've always thought that after transaction is committed all data is flushed automatically anyways" -- you are right. – xyz Jul 17 '17 at 09:54
  • But shouldn't flush be called after method `saveTransaction` is finished? Because now it seems like it's not (calling in manually as the last operation in method helps) – Fuv Jul 17 '17 at 10:40
  • pls show persistence.xml file and how you configure transaction – xyz Jul 17 '17 at 10:45
  • @xyz My persistence.xml contains attribute `transaction-type="JTA"`. – Fuv Jul 18 '17 at 08:46
  • @Andreas No method is annotated with `TransactionAttribute` annotation, so by default are set to `REQUIRED`. The transaction is commited though, because all other data is commited. Weird thing is that only this table seems to cause problems, cuz after executing the same flow - find, change, persist - on another entity it worked. Moreover this problematic entry is saved into db also after being selected (for example) with HQL query. – Fuv Jul 18 '17 at 08:51
  • @Flv I deleted my comments, because of the Answer I wrote below. – aschoerk Jul 18 '17 at 11:12
  • Please show complete code for `saveTransaction()` and `findById` – fg78nc Jul 18 '17 at 14:13

1 Answers1

1

According to the JPA-Documentation

"persist(Object entity)
Make an instance managed and persistent." 

means, persist can only be used for inserts. Normally you should get

"EntityExistsException - if the entity already exists. 
(If the entity already exists, the EntityExistsException may be 
thrown when the persist operation is invoked, or the 
EntityExistsException or another PersistenceException may be thrown at 
flush or commit time.)"

as the documentation states. So:

    T2 t2 = t2Repository.findById(id);
    t2.setProperty(someProperty);
    t2Repository.persist(t2);

according to JPA-definition should lead to EntityExistsException in any case, immediately or at the end of the transaction. This end can also be at the end of the method which itself calls TransactionService.persist. This Exception should lead to a rollback in any case, so your update will never be done.

My recommendation:

Get rid of the persist call, since the object becomes managed during find, the change will be done at the end of transaction.

See: does-jpa-hibernate-save-even-when-not-calling-persist

aschoerk
  • 3,333
  • 2
  • 15
  • 29
  • Your answer put me on the right track. I was updating two entites this way (find, change, persist). Although I wasn't getting any exceptions (Hibernate ignores these situations as it seems), but something must have been wrong. It is really weird, because one entity was updated and the other not, but after deleting both persist statements everything seems to be working like charm. Thanks! – Fuv Jul 19 '17 at 06:52