首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Java 中的悲观锁和乐观锁的兑现

2012-08-21 
Java 中的悲观锁和乐观锁的实现?锁(locking)?业务逻辑的实现过程中,往往需要保证数据访问的排他性。如在金

Java 中的悲观锁和乐观锁的实现

?

锁(locking)?
业务逻辑的实现过程中,往往需要保证数据访问的排他性。如在金融系统的日终结算 处理中,我们希望针对某个cut-off时间点的数据进行处理,而不希望在结算进行过程中 (可能是几秒种,也可能是几个小时),数据再发生变化。此时,我们就需要通过一些机制来保证这些数据在某个操作过程中不会被外界修改,这样的机制,在这里,也就是所谓 的“锁”,即给我们选定的目标数据上锁,使其无法被其他程序修改。 Hibernate支持两种锁机制:即通常所说的“悲观锁(Pessimistic Locking)” 和“乐观锁(Optimistic Locking)”。


一 :悲观锁(Pessimistic?Locking)?
悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定 状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能 真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系 统不会修改数据)。 一个典型的倚赖数据库的悲观锁调用:?select * from account where name=”Erica” for update 这条sql 语句锁定了account 表中所有符合检索条件(name=”Erica”)的记录。 本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。 Hibernate的悲观锁,也是基于数据库的锁机制实现。 下面的代码实现了对查询记录的加锁:

?

Query query = session.createQuery(hqlStr);
query.setLockMode( " user " ,LockMode.UPGRADE); // 加锁
List userList = query.list(); // 执行查询,

?获取数据?query.setLockMode?对查询语句中特定别名所对应的记录进行加锁(我们为 TUser类指定了一个别名“user”),这里也就是对返回的所有user记录进行加锁。 观察运行期Hibernate生成的SQL语句:?

table = " t_user "
dynamic - update = " true "
dynamic - insert = " true "
optimistic - lock = " version "
>
……
</ class >
</ hibernate - mapping > ?optimistic-lock属性有如下可选取值:?

? none 无乐观锁?
? version 通过版本机制实现乐观锁?
? dirty 通过检查发生变动过的属性实现乐观锁?
? all 通过检查所有属性实现乐观锁?

其中通过version实现的乐观锁机制是Hibernate官方推荐的乐观锁实现,同时也 是Hibernate中,目前唯一在数据对象脱离Session发生修改的情况下依然有效的锁机 制。因此,一般情况下,我们都选择version方式作为Hibernate乐观锁实现机制。?

2. 添加一个Version属性描述符?
代码内容

4 table = " t_user "
5 dynamic - update = " true "
6 dynamic - insert = " true "
7 optimistic - lock = " version "
8 >
9 < id
10 name = " id "
11 column = " id "
12 type = " java.lang.Integer "
13 >
14 < generator class = " native " >
15 </ generator >
16 </ id >
17 < version
18 column = " version "
19 name = " version "
20 type = " java.lang.Integer "
21 />
22 ……
23 </ class >
24 </ hibernate - mapping >

?注意version 节点必须出现在ID 节点之后。 这里我们声明了一个version属性,用于存放用户的版本信息,保存在TUser表的 version字段中。 此时如果我们尝试编写一段代码,更新TUser表中记录数据,如:?

3 List userList = criteria.list();
4 TUser user = (TUser)userList.get( 0 );
5 Transaction tx = session.beginTransaction();
6 user.setUserType( 1 ); // 更新UserType字段
7 tx.commit();

?每次对TUser进行更新的时候,我们可以发现,数据库中的version都在递增。 而如果我们尝试在tx.commit 之前,启动另外一个Session,对名为Erica 的用 户进行操作,以模拟并发更新时的情形:?

4 Session session2 = getSession();
5 Criteria criteria2 = session2.createCriteria(TUser. class );
6 criteria2.add(Expression.eq( " name " , " Erica " ));
7 List userList = criteria.list();
8 List userList2 = criteria2.list();TUser user = (TUser)userList.get( 0 );
9 TUser user2 = (TUser)userList2.get( 0 );
10 Transaction tx = session.beginTransaction();
11 Transaction tx2 = session2.beginTransaction();
12 user2.setUserType( 99 );
13 tx2.commit();
14 user.setUserType( 1 );
15 tx.commit(); ?执行以上代码,代码将在tx.commit()处抛出StaleObjectStateException异 常,并指出版本检查失败,当前事务正在试图提交一个过期数据。通过捕捉这个异常,我 们就可以在乐观锁校验失败时进行相应处理。?

?

?

热点排行