]
Juan F Cervera commented on HHH-3661:
-------------------------------------
Just for correctness,
Actually calculating the new version number, which I called step a), really happens in
the middle of the what I called step b), not before. This is part of the process in the
method scheduleUpdate which is called at line 151 of
org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity, after the
substitute variable was set to true on line 148 and before the substitution is applied on
line 156.
Another thing I'd like to clarify, even though it probably doesn't make any
difference, is that the bag I'm using is using a join table. See example below:
{noformat}
<bag name="typeBList" table="JOIN_TABLE"
inverse="false" cascade="none" >
<key column="ID_A" />
<many-to-many class="TypeB column="ID_B"
not-found="ignore" />
</bag>
{noformat}
Optimistic's locking version number is incorrectly applied to the
Entity in some cases
--------------------------------------------------------------------------------------
Key: HHH-3661
URL:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-3661
Project: Hibernate Core
Issue Type: Bug
Components: core
Affects Versions: 3.3.1
Environment: Hibernate 3.3.1.GA and Informix 10
Reporter: Juan F Cervera
Hi I have found an issue using optimistic locking and I think it's probably a bug.
The situation is the following:
a) I use optimistic locking
b) I have a legacy database where the optimistic locking field is controlled by triggers,
so I use generated="always" in the mapping file for the version field (I
don't think this is related to the problem, but wanted to clarify)
c) The Entity has a <bag> collection that can be empty (null)
d) At some point the collection is changed to something else than null, in my case this
is happening within the same transaction, after creating the Entity, but this doesn't
seem to be required for the problem to happen.
The above scenario produces a StaleStateException.
For what I see Hibernate first inserts the new record, then it does an update because we
have added the collection but it uses the wrong version number, which produces the
exception.
After some debugging I have traced down the problem, as follows:
a) As there has been a change to the Entity, Hibernate calculates a new version number
(even when I have generated="always". This is not normally a problem though as
it's not written to the DB.)
b) When an Entity has a collection that changes from null to something else, Hibernate
substitutes the normal collection for the appropriate Hibernate collection type, in my
case a PersistentBag. Unfortunately, the substitution process doesn't stop just at the
collection, it applies to all the dirty fields, including the version number to the new
calculated in a)!! This means that the version number is out of sync with the DB, which
will produce problems down the line.
See the following for details:
+ Line 112 at org.hibernate.event.def.WrapVisitor.processArrayOrNewCollection forces the
substitution by not returning new persistentCollection
+ This gets propagates several layers until it reaches the boolean "substitute"
in line 148 at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity
+ This variable enforces the substitution in the line 156, where the version number gets
updated to a new value which doesn't exist yet in the database, as the record has not
been updated with it yet.
c) When the update happens, Hibernate queries the Entity for it's version number
because it's using optimistic locking, and as this has been updated in b) with a new
value that doesn't match the record in the database nothing gets updated
See following for details:
+ The "previous" version number is retrieved in the line 96 at
org.hibernate.action.EntityUpdateAction.execute
d) Hibernate checks how many records have been updated, in this case 0 as the version
number was wrong. Then it interprets this as a StaleStateException
Unfortunately I don't know enough about Hibernate to be able to propose a working
solution. I think the fact that a full update of the Entity, including the new calculated
version number, is forced in step b) is the issue and that the version number should have
been left as it was.
How many other scenarios, apart from changing a null collection to one with data, would
produce substitute to be "true" I don't know, but I expect all those cases
to produce problems with optimistic locking in the same way.
I have work around for system that use the DB to control the version numbers instead of
Hibernate (normally through triggers). In these systems it's possible to set
optimistic-lock="false" in the collection, which would prevent the version
number changing for updates on that field, so the update on b) would be fine.
Unfortunately, if some other property changes along with the null collection, the version
number will change because of those other properties. So in order to be sure I don't
have issues I have had to set optimistic-lock="false" in all
components/properties/collections.
One more thing, I think this issue is probably the cause to the problem reported in
HHH-2796, as the symptoms look similar.
Let me know if you have any questions.
Thanks
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: