hibernate 乐观锁与悲观锁使用
hibernate 乐观锁与悲观锁使用
Hibernate支持两种锁机制: 
即通常所说的“悲观锁(Pessimistic Locking)”和 “乐观锁(OptimisticLocking)”。
悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
Hibernate的加锁模式有:
Ø LockMode.NONE : 无锁机制。
Ø LockMode.WRITE :Hibernate在Insert和Update记录的时候会自动
获取。
Ø LockMode.READ : Hibernate在读取记录的时候会自动获取。
以上这三种锁机制一般由Hibernate内部使用,如Hibernate为了保证Update
过程中对象不会被外界修改,会在save方法实现中自动为目标对象加上WRITE锁。
Ø LockMode.UPGRADE :利用数据库的for update子句加锁。
Ø LockMode. UPGRADE_NOWAIT :Oracle的特定实现,利用Oracle的for update nowait子句实现加锁。
Hibernate的悲观锁,也是基于数据库的锁机制实现。 下面的代码实现了对查询记录的加锁:
乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数 据库表增加一个“version”字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对 应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
1. 首先为TUser的class描述符添加optimistic-lock属性:![]() < hibernate - mapping >
 < hibernate - mapping >  
![]() < class
 < class  
![]() name = " org.hibernate.sample.TUser "
name = " org.hibernate.sample.TUser "  
![]() table = " t_user "
table = " t_user "  
![]() dynamic - update = " true "
dynamic - update = " true "  
![]() dynamic - insert = " true "
dynamic - insert = " true "  
![]() optimistic - lock = " version "
optimistic - lock = " version "  
![]() >
 >  
![]() ……
…… 
![]() </ class >
 </ class >  
![]() </ hibernate - mapping >
 </ hibernate - mapping >  
代码内容
即通常所说的“悲观锁(Pessimistic Locking)”和 “乐观锁(OptimisticLocking)”。
悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
Hibernate的加锁模式有:
Ø LockMode.NONE : 无锁机制。
Ø LockMode.WRITE :Hibernate在Insert和Update记录的时候会自动
获取。
Ø LockMode.READ : Hibernate在读取记录的时候会自动获取。
以上这三种锁机制一般由Hibernate内部使用,如Hibernate为了保证Update
过程中对象不会被外界修改,会在save方法实现中自动为目标对象加上WRITE锁。
Ø LockMode.UPGRADE :利用数据库的for update子句加锁。
Ø LockMode. UPGRADE_NOWAIT :Oracle的特定实现,利用Oracle的for update nowait子句实现加锁。
Hibernate的悲观锁,也是基于数据库的锁机制实现。 下面的代码实现了对查询记录的加锁:
1 ![]() String hqlStr  =   " from TUser as user where user.name=’Erica’ " ;
 String hqlStr  =   " from TUser as user where user.name=’Erica’ " ; 
2![]() Query query  =  session.createQuery(hqlStr);
Query query  =  session.createQuery(hqlStr); 
3![]() query.setLockMode( " user " ,LockMode.UPGRADE);  // 加锁
query.setLockMode( " user " ,LockMode.UPGRADE);  // 加锁  
4![]() List userList  =  query.list(); // 执行查询,
 List userList  =  query.list(); // 执行查询,
 String hqlStr  =   " from TUser as user where user.name=’Erica’ " ;
 String hqlStr  =   " from TUser as user where user.name=’Erica’ " ; 2
 Query query  =  session.createQuery(hqlStr);
Query query  =  session.createQuery(hqlStr); 3
 query.setLockMode( " user " ,LockMode.UPGRADE);  // 加锁
query.setLockMode( " user " ,LockMode.UPGRADE);  // 加锁  4
 List userList  =  query.list(); // 执行查询,
 List userList  =  query.list(); // 执行查询,获取数据 query.setLockMode 对查询语句中特定别名所对应的记录进行加锁(我们为 TUser类指定了一个别名“user”),这里也就是对返回的所有user记录进行加锁。 观察运行期Hibernate生成的SQL语句:
1 ![]() select tuser0_.id as id, tuser0_.name as name, tuser0_.group_id as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex from t_user tuser0_ where (tuser0_.name = ’Erica’ )  for  update
 select tuser0_.id as id, tuser0_.name as name, tuser0_.group_id as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex from t_user tuser0_ where (tuser0_.name = ’Erica’ )  for  update
 select tuser0_.id as id, tuser0_.name as name, tuser0_.group_id as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex from t_user tuser0_ where (tuser0_.name = ’Erica’ )  for  update
 select tuser0_.id as id, tuser0_.name as name, tuser0_.group_id as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex from t_user tuser0_ where (tuser0_.name = ’Erica’ )  for  update 这里Hibernate通过使用数据库的for update子句实现了悲观锁机制。 
上面这两种锁机制是我们在应用层较为常用的,加锁一般通过以下方法实现: 
Criteria.setLockMode 
Query.setLockMode 
Session.lock 
注意,只有在查询开始之前(也就是Hiberate 生成SQL 之前)设定加锁,才会 真正通过数据库的锁机制进行加锁处理,否则,数据已经通过不包含for update 子句的Select SQL加载进来,所谓数据库加锁也就无从谈起。
乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数 据库表增加一个“version”字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对 应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
1. 首先为TUser的class描述符添加optimistic-lock属性:
 < hibernate - mapping >
 < hibernate - mapping >   < class
 < class   name = " org.hibernate.sample.TUser "
name = " org.hibernate.sample.TUser "   table = " t_user "
table = " t_user "   dynamic - update = " true "
dynamic - update = " true "   dynamic - insert = " true "
dynamic - insert = " true "   optimistic - lock = " version "
optimistic - lock = " version "   >
 >   ……
……  </ class >
 </ class >   </ hibernate - mapping >
 </ hibernate - mapping >  添加一个Version属性描述符
代码内容
 1 ![]() < hibernate - mapping >
 < hibernate - mapping >   
2![]() < class
 < class   
3![]() name = " org.hibernate.sample.TUser "
name = " org.hibernate.sample.TUser "   
4![]() table = " t_user "
table = " t_user "   
5![]() dynamic - update = " true "
dynamic - update = " true "   
6![]() dynamic - insert = " true "
dynamic - insert = " true "   
7![]() optimistic - lock = " version "
optimistic - lock = " version "   
8![]() >
 >   
9![]() < id
 < id  
10![]() name = " id "
name = " id "   
11![]() column = " id "
column = " id "   
12![]() type = " java.lang.Integer "
type = " java.lang.Integer "   
13![]() >
 >   
14![]() < generator  class = " native " >
 < generator  class = " native " >   
15![]() </ generator >
 </ generator >   
16![]() </ id >
 </ id >   
17![]() < version
 < version  
18![]() column = " version "
column = " version "   
19![]() name = " version "
name = " version "   
20![]() type = " java.lang.Integer "
type = " java.lang.Integer "   
21![]() />
 />   
22![]() ……
……  
23![]() </ class >
 </ class >   
24![]() </ hibernate - mapping >
 </ hibernate - mapping >   
25![]() 
 
 < hibernate - mapping >
 < hibernate - mapping >   2
 < class
 < class   3
 name = " org.hibernate.sample.TUser "
name = " org.hibernate.sample.TUser "   4
 table = " t_user "
table = " t_user "   5
 dynamic - update = " true "
dynamic - update = " true "   6
 dynamic - insert = " true "
dynamic - insert = " true "   7
 optimistic - lock = " version "
optimistic - lock = " version "   8
 >
 >   9
 < id
 < id  10
 name = " id "
name = " id "   11
 column = " id "
column = " id "   12
 type = " java.lang.Integer "
type = " java.lang.Integer "   13
 >
 >   14
 < generator  class = " native " >
 < generator  class = " native " >   15
 </ generator >
 </ generator >   16
 </ id >
 </ id >   17
 < version
 < version  18
 column = " version "
column = " version "   19
 name = " version "
name = " version "   20
 type = " java.lang.Integer "
type = " java.lang.Integer "   21
 />
 />   22
 ……
……  23
 </ class >
 </ class >   24
 </ hibernate - mapping >
 </ hibernate - mapping >   25
 
 
 
注意version 节点必须出现在ID 节点之后。
 这里我们声明了一个version属性,用于存放用户的版本信息,保存在TUser表的 version字段中。 此时如果我们尝试编写一段代码,更新TUser表中记录数据,如: 
代码内容
1 ![]() Criteria criteria  =  session.createCriteria(TUser. class );
 Criteria criteria  =  session.createCriteria(TUser. class );  
2![]() criteria.add(Expression.eq( " name " , " Erica " ));
criteria.add(Expression.eq( " name " , " Erica " ));  
 Criteria criteria  =  session.createCriteria(TUser. class );
 Criteria criteria  =  session.createCriteria(TUser. class );  2
 criteria.add(Expression.eq( " name " , " Erica " ));
criteria.add(Expression.eq( " name " , " Erica " ));   
                    
                 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号