业务逻辑的实现过程中,往往需要保证数据访问的排他性。

这里就是所谓的“锁”,即给我们选定的目标数据上锁,使其无法被其他程序修改。

Hibernate支持两种锁机制:即通常所说的“悲观锁(Pessimistic Locking)”和“乐观锁(Optimistic Locking)”。

1. 悲观锁(Pessimistic Locking)

指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此在整个数据处理过程中,将数据处于锁定状态。

悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性。

一个典型的,依赖数据库实现的悲观锁调用:
select * from account where name=”Erica” for update
通过for update子句,这条SQL锁定了account表中所有符合检索条件的记录。本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。
Hibernate的悲观锁,也是基于数据库的锁机制实现。

例子:

String hqlStr = "from TUser as user where" +" user.name='Erica'";Query query = session.createQuery(hqlStr);query.setLockMode("user", LockMode.UPGRADE);//加锁List userList = query.list();//执行查询,获取数据

执行后的输出:

Hibernate: select tuser0_.id as id3_, tuser0_.name as name3_, tuser0_.age as age3_, tuser0_.group_id as group4_3_ from t_user3 tuser0_ where tuser0_.name='Erica' for update

query.setLockMode对查询语句中,特定别名所对应的记录进行加锁(我们通过”from TUser as user”为TUser类指定了一个别名“user”),这里也就是对返回的所有user记录进行加锁

可以看到Hibernate通过使用数据的for update子句实现了悲观锁机制。

2. Hibernate的加锁模式

1) LockMode.NONE: 无锁机制

2) LockMode.WRITE: Hibernate在Insert和Update记录的时候会自动获取

3) LockMode.READ: Hibernate在读取记录的时候会自动获取

以上这3种锁机制一般由Hibernate内部使用,如Hibernate为了保证update过程中对象不会被外界修改,会在save方法中自动为目标对象加上WRITE锁,这些都是Hibernate内部对数据的锁定机制,与数据库无关。

4) LockMode.UPGRADE: 利用数据库的for update子句加锁

5) LockMode.UPGRADE_NOWAIT: Oracle的特定实现,利用Oracle的for update nowait子句实现加锁

上面这两种锁机制是我们在应用层较常用的,依赖数据库的悲观锁机制。

加锁一般通过以下方法实现:

Criteria.setLockMode
Query.setLockMode
Session.lock
注:只有在查询开始之前(也就是Hibernate生成SQL之前)设定加锁,才会真正通过数据库的锁机制进行加锁处理,否则,数据已经通过不包含for update子句的select SQL加载进来,所谓数据库加锁也就无从谈起。

3. 乐观锁(Optimistic Locking)

悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销。

乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个“version”字段来实现。

读取出数据时,将此版本号一同读出,之后更新时,对此版本加1。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行对比,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

注:乐观锁机制往往基于系统中的数据存储逻辑,因此也具备一定的局限性,如在上例中,由于乐观锁机制是在我们的系统中实现,来自外部系统的操作不受我们系统的控制,因此可能会造成非法数据被更新到数据库中。

在系统设计阶段,我们应充分考虑到这些情况出现的可能性,并进行相应调整(如将乐观锁策略在数据库存储过程中实现,对外只开放基于此存储过程的数据更新途径,而不是将数据库表直接对外公开)。

Hibernate在其数据访问引擎中内置了乐观锁实现。

例子:

1》为TUser的class描述符添加optimistic-lock属性:

<hibernate-mapping><class name=”…TUser”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发生修改的情况下依然有效的锁机制。

2》 添加一个version属性描述符

<hibernate-mapping><class name=”…TUser”table=”t_user”dynamic-update=”true”dynamic-insert=”true”optimistic-lock=”version”><id name=”id”column=”id”type=”java.lang.Integer”><generator class=”native”></generator></id><version column=”version”name=”version”type=”java.lang.Integer”/>…
</class>
</hibernate-mapping>

注:version节点必须出现在id节点之后。
这里我们声明了一个version属性,用于存放用户的版本信息,保存在t_user表的version字段中。

3》测试

编写一段代码,更新TUser表中记录的数据

Criteria criteria = session.createCriteria(TUser.class);
criteria.add(Expression.eq(“name”,”Erica”));
List userList = criteria.list();
TUser user = (TUser)userList.get(0);
Transaction tx = session.beginTransaction();
user.setUserType(1);//更新UserType字段
tx.commit();

每次对TUser进行更新的时候,可以发现,数据库中的version都在递增。

而如果我们尝试在tx.commit之前,启动另外一个session,对名为Erica的用户进行操作,并模拟并发更新时的情形:

Session session=getSession();
Criteria criteria = session.createCriteria(TUser.class);
criteria.add(Expression.eq(“name”,”Erica”));
Session session2=getSession();
Criteria criteria2=session2.createCriteria(TUser.class);
criteria2.add(Expression.eq(“name”,”Erica”));
List userList = criteria.list();
List userList2 = criteria2.list();
TUser user = userList.get(0);
TUser user2 = userList2.get(0);
Transaction tx = session.beginTransaction();
Transaction tx2 = session2.beginTransaction();
user2.setUserType(99);
tx2.commit();
user.setUserType(1);
tx.commit();

执行以上代码,代码将在tx.commi()处抛出StaleObjectStateException异常,并指出版本检查失败,当前事务正试图提交一个过期数据。通过捕捉这个异常,我们就可以在乐观锁校验失败时进行相应处理。

转载于:https://blog.51cto.com/1831651/1224714

Hibernate深入浅出(六)事务2——锁locking相关推荐

  1. 数据库事务(Transaction)与锁(Locking)详解图析

    一.事务 事务(Transaction)是由一系列对系统中数据进⾏访问与更新的操作所组成的⼀个程序执行逻辑单元. 注:中止(abort):表示事务未成功结束,撤消事务的所有操作. 数据库应用程序通常通 ...

  2. 超详细图解!【MySQL进阶篇】MySQL事务和锁

    ACID 特性 在关系型数据库管理系统中,一个逻辑工作单元要成为事务,必须满足这 4 个特性,即所谓的 ACID: 原子性(Atomicity).一致性(Consistency).隔离性(Isolat ...

  3. mysql乐观锁与事务_[数据库事务与锁]详解七: 深入理解乐观锁与悲观锁

    注明: 本文转载自http://www.hollischuang.com/archives/934 在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库 ...

  4. 深入浅出Mysql - 优化篇(锁)

    深入浅出Mysql - 优化篇(锁) 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保 ...

  5. 具体解释Hibernate中的事务

    1.前言 上一篇博客解说了Hibernate中的一级缓存,属于Session级别的.这篇博客解说一下Hibernate中的事务机制. 有关事务的概念.请參照通俗易懂数据库中的事务.  2.怎样处理Hi ...

  6. 深入浅出MySQL事务处理和锁机制

    深入浅出MySQL事务处理和锁机制 2015-01-13 架构师之旅 1. 事务处理和并发性 1.1. 基础知识和相关概念 1 )全部的表类型都可以使用锁,但是只有 InnoDB 和 BDB 才有内置 ...

  7. MySQL之事务、锁

    锁 一.概念 锁是计算机协调多个进程或线程访问某一个资源的机制.在数据库中,除传统的计算资源(CPU.RAM.IO)的争用意外,数据也是一种许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所 ...

  8. ORM中的事务和锁、Ajax异步请求和局部刷新、Ajax文件上传、日期时间类型的Json、多表查询图书系统

    一.ORM中的事务和锁 事务 事务要确保原子性 """ 事务ACID原子性:不可分隔的最小单位一致性:跟原子性是相辅相成隔离性:事务之间相互不干扰持久性:事务一旦确认永久 ...

  9. 深入理解Mysql - 事务与锁原理

    一.事务的定义 事务是数据库管理系统执行过程中的一个逻辑单位,有一个有限的数据库操作序列构成.mysql 的存储引擎中只有InnoDB支持事务. 二.事务的四大特性 原子性(Atomicity):原子 ...

  10. 第十六章——处理锁、阻塞和死锁(3)——使用SQLServer Profiler侦测死锁

    原文: 第十六章--处理锁.阻塞和死锁(3)--使用SQLServer Profiler侦测死锁 前言: 作为DBA,可能经常会遇到有同事或者客户反映经常发生死锁,影响了系统的使用.此时,你需要尽快侦 ...

最新文章

  1. linux怎么进入root文件,linux下安装ROOT过程
  2. oracle存储过程调用游标例子
  3. ZZULIOJ 1130: 杨辉三角
  4. 父组件向子组件传递数据
  5. java使用Pattern、Matcher调用正则表达式
  6. L1、L2正则化区别和数学原理,以及什么是Elastic Net(弹性网络)正则项
  7. Endnote--在参考文献列表中添加DOI
  8. 2021年北京高校数学建模校际联赛题目出版社图书印制策略解题论文及程序
  9. java开发 微信商家转账到零钱,发起商家转账API,微信支付
  10. Hololens学习(一)安装 部署Hololens开发环境
  11. vue常用的时间、手机号等的格式化方法
  12. 投资学实务 期货日志及实践总结
  13. 敏涵化妆品何以圈粉Z世代消费群体?
  14. python数据分析案例分析题_Python数据分析-案例分析
  15. jquery遍历得到的 Map 数据,
  16. python如何安装第三方模块
  17. rxbus 源码_RxBus的实现及简单使用
  18. 大学模电实验合集丨实验六 比例求和运算电路
  19. cmwap和cmnet的网速
  20. 国家代码/地区代码查询[外贸免费工具]

热门文章

  1. 中文问题-Mobile-UrlEncode
  2. MSCRM4.0显示图片格式附件
  3. CF1096F Inversion Expectation
  4. 10 使用ViewPager实现导航
  5. Java continue的关键字
  6. Sql 行转换列(列转换行), JavaScript解决思路
  7. 选择尽可能多的不相交区间
  8. Windows设计师:多核芯片要求全新操作系统
  9. 精选|2018年12月R新包推荐
  10. 从一个小问题洞察挣钱秘籍,却被90%的数据分析师忽略