speedster wrote:
Humm... Not completely.
I don't understand why a call to a setter after a call to the lock() method will perform an update.
This is one of the cool features of Hibernate - once an object is 'persistant,' any modifications you make to the state of that object will be propagated to the database automatically.
This is all in the manual, but in short, an object can be in three states as far as Hibernate is concerned: Transient, Persistant, or Detatched.
A Transient object is like a brand new object with no state stored in the database. It's a regular POJO:
Code:
SomeObject obj = new SomeObject("param1", 2);
That's a transient object - it isn't stored in a database.
A Persistant object, on the other hand, is an object which
has been persisted to the database. A Persistant object (roughly) corresponds to a row in the database. For an object to be persistant, it must be 'associated' with a Hibernate Session object. The Session needs to know about your object for it to be 'persistant.' Any object that you retrieve from the database is associated with the Session you used to retrieve it.
The third type of object, a detatched object, is what you call a persistant object once the session it's associated with is closed.
Now, back to your post. Hibernate detects changes to persistant objects, and automatically generates UPDATE statements for those changes. Typically the UPDATE happens when you commit the transaction, but it could happen before that, or you could make it happen by flushing the Session. This is a pretty cool feature.
Consider the Javadoc comments for the update() and lock() methods:
Code:
lock():
Obtain the specified lock level upon the given object. This may be used to perform a version check (LockMode.READ), to upgrade to a pessimistic lock (LockMode.UPGRADE), or to simply reassociate a transient instance with a session (LockMode.NONE). This operation cascades to associated instances if the association is mapped with cascade="lock".
update():
Update the persistent instance with the identifier of the given detached instance. If there is a persistent instance with the same identifier, an exception is thrown. This operation cascades to associated instances if the association is mapped with cascade="save-update".
The comments are a bit confusing, I suppose. I think 'transient instance' in the comment for lock() should really be 'detatched instance,' as I've used the term in this post.
In the comment for update(), it seems as though 'persistant instance' is meant to mean 'state stored in the database,' while the reference to 'detatched instance' here is correct.
Now, back to the code in your original post:
Code:
// foo is an instance loaded by a previous Session
foo.setProperty("bar");
session = factory.openSession();
session.saveOrUpdate(foo);
session.flush();
session.connection().commit();
session.close();
Remember that Hibernate can detect changes to a
persistant object, but not a
detatched object. What you would want to do is make the detatched object foo persistant
before you change its property:
Code:
session = factory.openSession();
tx = session.beginTransaction();
session.lock(foo, LockMode.NONE); // make foo persistant, without generating an UPDATE statment
foo.setProperty("bar"); // Hibernate will now detect this change
tx.commitTransaction(); // this will result in the UPDATE
session.close();