users@glassfish.java.net

Re: EntityExistsException

From: Roman Borschel <r.borschel_at_gmx.net>
Date: Wed, 3 Mar 2010 11:53:54 +0100

Hi,

On Mar 3, 2010, at 10:46 AM, Markus Karg wrote:

> The strange thing is that the algorithm actually is:
>
> Integer id = SELECT MAX(o.id) FROM Appointment o
> Appointment a = new Appointment(1 + id);
> em.persist(a);
> em.persist(a); // We meanwhile detected this obsolete invocation
>
> There is no @version used, so optimistic locking cannot be the
> problem.
>
> As this call runs in a SLSB with TX=REQUIRED, it obviously cannot
> create duplicate IDs!

I think it can, unless this particular transaction has a SERIALIZED
isolation level. Default is READ COMMITTED for most databases.

Thread A starts transaction
Thread B starts transaction
Thread A reads MAX(o.id)
Thread B reads MAX(o.id)
Thread A creates new Appointment with 1+id
Thread A commits its transaction
Thread B creates a new Appointment with id+1
=> The Persistence context checks for existance of this ID and it
exists. It sees the committed entry from thread A (READ COMMITTED).
=> The persistence context assumes the entity is detached because the
ID exists
=> Detached entity passed to persist() is illegal and thus you get
EntityExistsException

Just a guess, I might be wrong.

Generally, creating primary keys this way is pretty fragile and I
would not recommend it.

Maybe this helps

Roman