Kava Pava Gava Tava Nava Zava Java

everything about Java
随笔 - 15, 文章 - 0, 评论 - 1, 引用 - 0
数据加载中……

总结 Hibernate 的 Optimistic Concurrency Control

阅读 Hibernate Reference 第11章11.3后我的总结以及理解:

(1)带有版本标记的 Optimistic Concurency Control 是唯一既能提供高度并发,又能提供可扩展性的解决方案。就是说,很多人可以一起对一些数据同时进行操作,而这些操作又尽量不会造成互相冲突。

(2)在并发要求低的环境里(没有很多用户,没有很多更新,大家不会同时对一个数据操作,或者即使造成冲突后果也不严重),如果干脆不进行版本检查,会得到“last commit wins”的结果,就是说最后 commit 的数据覆盖之前 commit 的数据。如果两个对话重叠,之前commit 的数据可能被后 commit 的数据覆盖,从而丢失。而且整个过程没有任何出错,会造成用户迷惑。

(3)Extended session and automatic versioning

用户的会话 (conversation) 通常包括多个步骤,即取出数据,操作数据,然后保存数据回数据库。这样的会话会跨越几个 http 来回,持续一段时间。Extended session and automatic versioning 在整个会话中只使用一个 hibernate session。在会话初始获得 session,仅在会话结束时进行 session.flush(); ... session.close()。

一个 hibernate session 并不对应一个 JDBC connection。开始一个transaction的时候获得一个新的连接,并且 resume session;commit transaction 的时候切断 hibernate session 和 JDBC connection 的连接,也就是将 connection 还给连接池。在一个 hibernate session 中,也就是,在这种方式(Extended session)中,仍然动态地使用 JDBC connection,不会造成占用太多 connection。早先版本的 hibernate 需要写代码 disconnect / recommect 一个 hibernate session。现在已经不需这样做(deprecated)。开始/结束 transaction 产生同样效果。

如果在session和JDBC connection重新连接的时候,如果希望强制检查应用程序没有进行更新,但是有可能被其他 transaction 更新的对象的版本,可以用该对象以及LockMode.READ作为参数调用 Session.lock()。Session.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". ”Session.lock()的声明如下:

public void lock(Object object,
                 LockMode lockMode)
          
throws HibernateException

采用 extended session 这种方式,所使用的 Session 通常被设置为 FlushMode.MANUAL,这样仅仅在最后一个 transaction 周期(上面说到,一个Session可以有多个transaction)才允许进行向数据库保存数据的操作。这个最后的 transaction 包含了 flush() 和 close() 操作,来结束对话。

采用 extended session 的问题是,session 可能保存了很多数据,占据很大空间,而用户考虑的时间可能很长,就是说会话持续的时间很长,这样保存 session 在一个长时间的会话中可能会造成困难。比如说,HttpSession中应该只保存很少的数据。(HttpSession可能要在各个服务器之间传递)因为 Session 实际上是所有取出来的对象的第一级缓存,因此最好仅仅将 extended session 用在有限的几个 request / response 组成的会话中。一个 Session 只用在一个会话中,因为(否则?)Session中很快就会出现不同步(陈旧)的数据。

Disconnected session 应该被放在持久层。可以把它放在 EJB stateful session bean 中。不要把 Session 交给 web 层,或者放在 HttpSession 中。

使用 session-per-conversion (也就是 extended session),更难实现自动 current session context 管理(没法用 ThreadLocalSessionContext了)。需要自己实现 CurrentSessionContext。更多的需要阅读 Hibernate Wiki。

(4)Detached objects and automatic versioning

这种方法,在每次和数据库打交道的时候打开一个新的 Session。但是每次和数据库打交道的时候重复使用同样的持久对象实例。应用程序从一个Session中调出持久对象,对它们(此时已经 detached)进行操作,然后调用另一个 Session 的 update(), saveOrUpdate() 或者 merge(),将它们 reattach 回这个 Session。

注意 update(), saveOrUpdate(), merge() 的区别。引用 Hibernate Reference 10.7 “Usually update() or saveOrUpdate() are used in the following scenario: ...... and merge() is very different”

Hibernate 在 flush 的时候检查版本,如果有冲突,抛出异常。

如果确信(笔者认为应该说希望确信)对象没有被更改,可以如同上面所说的调用 lock(),而不是update()。

(5)定制自动版本检查

映射属性 optimistic-lock 定制自动版本检查。

false: 关闭检查

all: 检查所有的栏位,而不是版本栏位。这种方法可以对没有版本栏位也无法添加版本栏位的数据库表进行检查。理论上来说,这种方法只能用于 extended session 而不是 session per request with detached objects,也就是上面说的方法(3)而不是(4)。原因是,这种方法需要在 Session 中保存有老的数据,以便比较老的数据和数据库中的当前数据,来确定是否有冲突。

dirty: 仅仅在 flush 时比较更改过的(dirty)数据在数据库中有没有被其他 transaction 修改过,以便避免冲突。这种方法可以允许同时修改一行数据中的不重叠的字段。我的理解,dirty 同 all 一样,都只能在 extended session 中使用,以便利用 extended session 中保存的老的数据进行比较(版本检查)。

所有以上情况,不管是使用版本栏目,还是 all 或 dirty,Hibernate 都在一个 UPDATE 语句中完成检查和更新(在 Where 从句中设置检查条件)。

最后,如果设置了 transitive persistence 到关联管理的从属 entity,hibernate 可能会执行不必要的 update。这通常不是问题。但是,如果有数据库 trigger 关联到 update 时,可能实际上没有更新但是会引发 trigger。可以设置 select-before-update="true" 强制 hibernate 在更新前进行 select。

posted on 2009-12-16 12:27 bing 阅读(1597) 评论(0)  编辑  收藏 所属分类: Hibernate


只有注册用户登录后才能发表评论。


网站导航: