Search code examples
javajakarta-eetransactionsejbcommit

EJB Transaction misunderstanding


I am calling SLSB method which transaction controlled by container. In method I am trying to remove entity and create new one

List<FactPlan> factPlans = factPlanFacadeLocal.findAll();

for (FactPlan factPlan : factPlans) {
    factPlanFacadeLocal.remove(factPlan);
}

FactPlan factPlan = new FactPlan(12264L, 12088L);
factPlanFacadeLocal.create(factPlan);

And I have following exception

Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "pkfact_plan"
Detail: Key (fact_id, plan_id)=(12264, 12088) already exists.

What am I doing wrong?

UPD: JPA implementation is EclipseLink


Solution

  • Edit: I was wrong in saying you need to commit, a flush is enough after your remove operations for ensuring the DB constraints are not violated.

    What is happening (it is exactly the same for EclipseLink as well):

    Hibernate is only seeing what is happening in memory inside the Persistence Context of your transaction, without flushing it is unable to validate DB constraints preemptively (primary key in this case). While Hibernate is perfectly aware of you already removing the item with the same ID (since it all happened in the same Persistence Context), the DB isn't seeing any of your changes until the flush.

    Now you would think that why isn't it enough to let the flush happen automatically when the transaction ends, before the commit? Surely the order of DB operations will be consistent with the JPA operations and the DB will see the row removal before the insert. Well it won't, Hibernate is changing the order of your operations and it puts all insertion before deletion breaking the DB constraint: http://docs.jboss.org/hibernate/orm/3.5/javadocs/org/hibernate/event/def/AbstractFlushingEventListener.html#performExecutions%28org.hibernate.event.EventSource%29