Hibernate的LockMode(悲观锁和乐观锁)

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子句实现加锁。
乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个“version”字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

 

悲观锁

 

    在应用程序中显示地为数据资源加锁.悲观锁假定当前事务操纵数据资源时,肯定还会有其它事务同时访问该数据资源,为了避免当前事务的操作受到干扰,先锁定资源.尽管悲观锁能防止丢失更新和不可重复读这类并发问题,但会影响并发性能.(简单理解,就是每次在操作数据时总是悲观地认为会有别的事务也会来操纵同一数据,从此锁住该笔数据,直到自己操作完成后再解除锁

 

乐观锁

 

    假定当前事务操纵数据资源时,不会有其它事务同时访问该数据资源,因此完全依靠数据库的隔离级别来自动管理锁的工作.应用程序采用版本控制手段来避免可能出现的并发问题.(所谓乐观锁,它通常认为多个事务同时操纵同一数据的情况是很少的,因为根本不做数据库层次上的锁定,只是基于数据的版本标识实现应用程序级别上的锁定机制,既保证了多个事务的并发访问,又有效地防止了第二类丢失更新的出现

 

 

LockMode类表示的几种锁定模式

 

锁定模式

描述

LockMode.NONE

 

如果缓存中存在对象,直接返回该对象的引用,否则通过select语句到数据库中加载该对象,默认值.

LockMode.READ

 

不管缓存中是否存在对象,总是通过select语句到数据库中加载该对象,如果映射文件中设置了版本元素,就执行版本检查,比较缓存中的对象是否和数据库中对象版本一致

LockMode.UPGRADE

 

不管缓存中是否存在对象,总是通过select语句到数据库中加载该对象,如果映射文件中设置了版本元素,就执行版本检查,比较缓存中的对象是否和数据库中对象的版本一致,如果数据库系统支持悲观锁(如Oracle/MySQL),就执行select...for update语句,如果不支持(如Sybase),执行普通select语句

LockMode.UPGRADE_NOWAIT

 

和LockMode.UPGRADE具有同样功能,此外,对于Oracle等支持update nowait的数据库,执行select...for update nowait语句,nowait表明如果执行该select语句的事务不能立即获得悲观锁,那么不会等待其它事务释放锁,而是立刻抛出锁定异常

LockMode.WRITE

 

保存对象时会自动使用这种锁定模式,仅供Hibernate内部使用,应用程序中不应该使用它

LockMode.FORCE

 

强制更新数据库中对象的版本属性,从而表明当前事务已经更新了这个对象

 

 

多个事务并发运行时的并发问题

 

第一类丢失更新:撤销一个事务时,把其它事务已提交的更新数据覆盖.

第二类丢失更新:不可重复读中的特例,一个事务覆盖另一事务已提交的更新数据.

脏读:一个事务读到另一事务未提交的更新数据.

幻读:一个事务读到另一事务已提交的新插入的数据.

不可重复读:一个事务读到另一个事物已提交的更新数据.

 

锁的类型和兼容性

 

共享锁

 

 加锁条件:当一个事务执行select语句时,数据库系统会为这个事务分配一把共享锁,锁定被查询的数据.

 解锁条件:数据被读取后,数据库系统立即解除共享锁.

 与其它锁的兼容性:如果数据资源上放置了共享锁,还能再放置共享锁和更新锁.

 并发性能:良好的并发性能.当多个事务读相同数据时,每个事务都会获得一把共享锁,可以同时读锁定的数据.

 

独占锁

 

 加锁条件:当一个事务执行insert,update,delete时,数据库系统会自动对SQL语句操纵的数据资源使用独占锁.如果该数据资源已经有其它锁存在时,无法对其再放置独占锁.

 解锁条件:独占锁一直到事务结束后才能被解除.

 与其它锁的兼容性:独占锁不能和其他锁兼容,如果数据资源已经加上了独占锁, 就不能再放置其它锁,同样,如果已经有了其它锁,就不能放置独占锁.

 并发性能:并发性能较差,只允许有一个事务访问锁定的数据,如果其他事务也需要访问该数据,就必须等待,直到前一个事务结束,解除了独占锁,其它事务才能访问该数据.

 

更新锁

 

 加锁条件:当一个事务进行update操作时,数据库系统会先为事务分配一把更新锁.

 解锁条件:当读取数据完毕,执行更新操作时,会把更新锁升级为独占锁.

 与其它锁的兼容性:更新锁与共享锁兼容,即一个资源可以同时放置更新锁和共享锁,但是最多只能放置一把更新锁,这样,当多个事务更新相同的数据时,只有一个事务能获得更新锁,然后再把更新锁升级为独占锁,其它事务必须等到前一个事务结束后,才能获得更新锁,避免了死锁.

 并发性能:允许多个事务同时读锁定资源,但不允许其它事务修改它.

 

 

各种隔离级别所能避免的并发问题

 

隔离级别

是否出现第一类丢失更新

是否出现第二类丢失更新

是否出现脏读

是否出现幻读

是否出现不可重复读

 

Serializable串行化

    否

    否

  否

     否

    否

 

RepeatableRead可重复读

    否

    否

  是

     否

    否

 

ReadCommited读已提交数据

    否

    否

  是

     是

    是

 

ReadUncommited读未提交数据

    否

    是

  是

     是

    是



悲观锁与乐观锁的比较:
悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受;
相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。乐观锁机制往往基于系统中的数据存储逻辑,因此也具备一定的局限性,如在上例中,由于乐观锁机制是在我们的系统中实现,来自外部系统的更新操作不受我们系统的控制,因此可能会造成脏数据被更新到数据库中。在
系统设计阶段,我们应该充分考虑到这些情况出现的可能性,并进行相应调整(如将乐观锁策略在数据库存储过程中实现,对外只开放基于此存储过程的数据更新途径,而不是将数据库表直接对外公开)。
Hibernate 在其数据访问引擎中内置了乐观锁实现。如果不用考虑外部系统对数据库的更新操作,利用Hibernate提供的透明化乐观锁实现,将大大提升我们的生产力。
Hibernate中可以通过class描述符的optimistic-lock属性结合version描述符指定。
optimistic-lock属性有如下可选取值:
Ø none
无乐观锁
Ø version
通过版本机制实现乐观锁
Ø dirty
通过检查发生变动过的属性实现乐观锁
Ø all
通过检查所有属性实现乐观锁
其中通过version实现的乐观锁机制是Hibernate官方推荐的乐观锁实现,同时也是Hibernate中,目前唯一在数据对象脱离Session发生修改的情况下依然有效的锁机制。因此,一般情况下,我们都选择version方式作为Hibernate乐观锁实现机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值