Hi
I’m currently writing a web application and face (as everyone else) the problem of data inconsistency because I didn’t implement locking. That’s why I decided to implement optimistic locking using a version field in every object. My problem is now that I save the version number in my request, load the object before I save it and overwrite the eventually new version number with the old one. I do this to give Hibernate the chance to detect if something changed. See below for a more complete description.
Have a look at the following sequence
First User clicks edit
- Hibernate Session is opened
- load the record from the database and store the Id, version number and other attribs in the request
- Hibernate Session is closed
- User sees the edit page
- User changes an attrib (no save so far)
A second user click edit
- Hibernate Session is opened
- load the same record from the database and store the Id, version number and other attribs in the request (note all attribs are the same as in the first load we didn’t change anything)
- Hibernate Session is closed
- User sees the edit page
-
- User changes an attrib (no save so far)
- User clicks save
- Hibernate Session is opened
- I reload the object (have to get it from somewhere and some attribs cannot be changed by the user and are therefore not stored in the request)
- The “user” attribs in the object are overwritten
- The version is overwritten with the old version number stored in the form. Note: This time the version numbers are the same as no one changed the object.
- The object is stored (upodate) in the database and the version number is automatically increased
- Hibernate Session is closed
The First user click save
- Hibernate Session is opened
- I reload the object (have to get it from somewhere and some attribs cannot be changed by the user and are therefore not stored in the request)
- The “user” attribs in the object are overwritten
- The version is overwritten with the old version number stored in the form. Note: This time the version numbers differ the “new” version number from the updated object is overwritten with the “old” version number from the form/original object
- The object is stored (update) in the database and the version number is automatically increased.
This is where the unexpected behavior starts. The object is updated! And the version number is increased (“new new version” = “new version” + 1).
- Hibernate Session is closed
I guess the problem is that Hibernate ignores the version number set in the object and uses a version number that is somehow internally connected to the object. How can I tell hibernate to use the version number stored in my object or how can I overwrite the internal version number?
I guess another solution would be to not load the object and recreate it completely new. The only problem is that my object also contains lots of attributes that the user cannot overwrite and I would like to avoid to copy those fields over all the time.
Please see below for the pseudo java classes, the mapping and the pseudo code.
Thanks in advance for any help
Rgds
Ralph
----------------
Class myObject
{
long mVersion;
public long getVersion()
{
return mVersion;
}
public void setVersion(long aVersion)
{
mVersion = aVersion;
}
private String mId;
public String getId()
{
return mId;
}
void setId(final String aId)
{
mId = aId;
}
}
----
the mapping file
<hibernate-mapping>
<class
name="com.avaya.rba.dom.model.Customer"
table="Customer"
dynamic-update="true"
dynamic-insert="false"
>
<id
name="id"
column="ID"
type="java.lang.String"
length="32"
unsaved-value="none"
>
<generator class="uuid.hex">
</generator>
</id>
<version
name="version"
type="long"
column="version"
access="property"
unsaved-value="negative"
/>
</class>
</hibernate-mapping>
--- the struts form
Class myForm extends ActionForm
{
long mVersion;
public long getVersion()
{
return mVersion;
}
public void setVersion(long aVersion)
{
mVersion = aVersion;
}
}
----
Thread1 - load the object
// get the thread session
Session session = getSession(….);
MyObject mo = Session.load(myObjectId);
myForm mf = Struts.getForm(…)
mf.setId(mo.getId);
mf.setVersion(mo.getVersion);
session.close
End Thread 1
----
Thread2 - save the object
// get the thread session
Session session = getSession(….);
myForm mf = Struts.getForm(…)
// load the object which was possibly changed …
MyObject mo = Session.load(mg.getId());
// copy the old version into the loaded object so that Hibernate can do the Version check
mo.setVersion(mf.getVersion());
// here I would expect a Stale object exception if someone else changed the object between Thread1 and Thread2. Instead the object is updated.
session.update(mo);
End Thread 1
Code:
Code:
Code: