hibernate在什么时候才会去检测持久化对象的version?

sulong 于 2008-01-09 说两句 »

如果在映射时,定义了 optimistic-lock=”version”,同时映射了  , 那么就会起用hibernate的乐观锁机制。hibernate会在执行update merge等更新操作时对比数据库里的该行的version和当前对象的version是否一样,如果一样则更新,不一样则出异常。但并 hibernate并不会在所有的更新操作时都做去对比这个version。

乐观锁 是用来处理并发事务的。如果有多个事物同时对一行数据进行更新,那么才会检测这个version;反之,如果在一个事务内部,无论对version做怎么 样的更改,都不会检测。那么hibernate是如何做到这一步的呢?在每个事务提交的时候,hibernate会判断当前事务里有哪些对象被更新到数据 库里,如果这个对象处理持久化状态,则不检查它的version,如果处于游离态,则要在更新前检查version。

换句话说, 如果对象是在当前的事物里通过load方法,get方法,或者通过query等查询出来的,那么这个对象在当前事物里处于持久化状态,hibernate 就不会检测version。如果对象不是在当前事务中被从数据库中读出来的,而是程序新建,或者是前一个事务或前一个session里取出来的,那么在当 前事务里它就处于游离态,hibernate就会检version。

例如,有一个类Person,需要更新属性name。于你查出这个对象把这个对象在页面显示,并且让用户在页面上更改完成并提交时,form里包含那个对象的id,要更新的字段name和version。这样当用户提交后,在后台,如果你是这样做的:

1
2
3
4
5
6
7
8
//......
Transaction transaction = session.beginTransaction();
Person person = (Person) session.load( Person. class , id);
person.setName(name);
person.setVersion(version);
session.update(person);
transaction.commit();
//......

上 面那种情况,因为被update的person是从当前事务中查询出来的,正处于持久化状态,所以在更新时,就算页面传来的version值比前数据库里 的version值小,hibernate也不会报错,因为它根本就不会检测。如果想让hibernate检测,你可以这样做:

1
2
3
4
5
6
7
8
9
//......
Transaction transaction = session.beginTransaction();
Person person = new Person();
person.setId(id);
person.setName(name);
person.setVersion(version);
session.update(person);
transaction.commit();
//......

由于是新建出来的person,这时的person处于游离态,所以在后面的更新时,hibernate就会按照你的意愿去检测version 了。

但 是上面的方法还是有问题,就是如果那个Person里有很多个属性,而你只要改其中一部分,如果你不把所有的属性都扔到页面上,再在回来时写入新建的 person里,那么在更新时,很可能会就会把一些你不想被更新字段给覆盖掉。而且,如果person和其它对象有外键关联,就更麻烦了。在这样的情况 下,还是从数据库里取出当前对象,并更新它的那几个字段来得方便,不过这个时候如果你真的需要检测version,估计只好手动判断version 的值是否正确了。

 

 

http://sulong.me/2008/01/09/when_will_hibernate_check_version_of_object