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