业务逻辑的实现过程中,往往需要保证数据访问的排他性。因此,我们就需要通过一些机制来保证这些数据在某个操作过程中不会被外界修改,这样的机制,在这里,也就是所谓的“锁”,即给我们选定的目标数据上锁,使其无法被其它程序修改。

Hibernate 支持两种锁机制:

1. 悲观锁(Pessimistic Locking)

从加载对象就开始锁定。修改过程中一直是锁。直到事务commit()提交后再解锁。

session.load(Info.class,"p003",LockOptions.UPGRADE);

public class TestPessimisticLock extends TestCase {@Testpublic void testLock1(){Session session = null;try {session = HibernateUtil.getSession();//开始锁定,下面的testLock2不能执行session.beginTransaction();Info data = session.load(Info.class, "p003", LockOptions.UPGRADE);data.setName("1111111");session.getTransaction().commit();//执行以后才解锁,这时testLock2才可以执行}  catch (Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally{HibernateUtil.closeSession();}} @Testpublic void testLock2(){Session session = null;try {session = HibernateUtil.getSession();session.beginTransaction();Info data = session.load(Info.class, "p003", LockOptions.UPGRADE);data.setName("2222222");session.getTransaction().commit();}  catch (Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally{HibernateUtil.closeSession();}}
}

2. 乐观锁(Optimistic Locking)

并不是真的锁,是在提交时间进行冲突检测。把里面的内容与刚开始读取的内容对照一下,有问题就抛异常。相对于悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。

悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个"version"字段来实现。

乐观锁的工作原理 :

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

配置:

1.在数据库表中加一个字段version

如果是数据库后加的version字段,那么实体类中必须要加上version并生成get、set方法

public class Info implements java.io.Serializable {private String code;private Nation nation;private String name;private Boolean sex;private Date birthday;private Set families = new HashSet(0);private Set works = new HashSet(0);private int version;//实体类中也要有version,并生成getter和setterpublic int getVersion() {return version;}public void setVersion(int version) {this.version = version;}

2.在映谢文件中配置<version name="version"> 这里注意version的位置,一定是要放置在id的后面

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-3-11 10:12:32 by Hibernate Tools 5.2.0.CR1 -->
<hibernate-mapping><class name="com.itnba.maya.model.Info" table="info" catalog="mydb" optimistic-lock="version"><cache usage="read-only"/> <id name="code" type="string"><column name="Code" length="50" /><generator class="assigned" /></id><!-- 配置version,位置放在<id></id>下面 --><version name="version"></version><many-to-one name="nation" class="com.itnba.maya.model.Nation" fetch="select"><column name="Nation" length="50" /></many-to-one><property name="name" type="string"><column name="Name" length="50" /></property><property name="sex" type="java.lang.Boolean"><column name="Sex" /></property><property name="birthday" type="timestamp"><column name="Birthday" length="19" /></property></class>
</hibernate-mapping>

配置完成后代码不用改变

由乐观锁引发的问题 

当两个不同的事务同时读取到一条数据并进行修改时,这个时候程序就会抛出org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)异常。

这里同样有两种情况

一种是两个不同的事务的情况

@Test
public void testTransation1(){  Session session1 = null;  Session session2 = null;  try{  session1 = HibernateUtil.getSession();  session2 = HibernateUtil.getSession();  Info info1= session1.load(Info.class, "p003");  Info info2 = session2.load(Info.class, "p003");  Transaction tx1 = session1.beginTransaction();  info1.setName("2222222"); tx1.commit();  Transaction tx2 = session2.beginTransaction();  info2.setName("11111111");  tx2.commit();  System.out.println("事务2提交");  }catch(Exception e){  e.printStackTrace();  }finally{  if(session1 != null){  session1.close();  }  if(session2 != null){  session2.close();  }  }
} 

事务2提交时发现version的值不一样,这个时候就会抛出org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)异常.

第二种情况是子事务的情况

@Test
public void testTransation2(){  Session session1 = null;  Session session2 = null;  try{  session1 = HibernateUtil.getSession();  session2 = HibernateUtil.getSession();  Info info1= session1.load(Info.class, "p003");  Info info2 = session2.load(Info.class, "p003");  Transaction tx1 = session1.beginTransaction();Transaction tx2 = session2.beginTransaction(); info2.setName("11111111");   tx2.commit(); info1.setName("2222222");   tx1.commit();}catch(Exception e){  e.printStackTrace();  }finally{  if(session1 != null){  session1.close();  }  if(session2 != null){  session2.close();  }  }
}          

我们发现事物2被包裹在事务1里面,如果Dir被配置为延迟加载(hibnernate默认就是延迟加载的)的,这个时候在事务1进行提交的时候,会先去数据库进行查询一下,再进行更新操作。

如果Dir被配置为非延迟加载(lazy="false")的,这个时候事务1在提交的时候就不会先去查询数据库,而是直接提交,在提交的时候发现version不匹配,因而也会抛出org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)异常 .

解决办法

1、捕获StaleObjectStateException异常,提示数据过时已被修改,让用户重新提交

2、尽量从业务方面去减小事务块,事务块越大,由乐观锁引起的问题的概率就越大

转载于:https://www.cnblogs.com/claricre/p/6543051.html

hibernate悲观锁,乐观锁相关推荐

  1. Hibernate悲观锁/乐观锁

    如果需要保证数据访问的排它性,则需对目标数据加"锁",使其无法被其它程序修改 一,悲观锁 对数据被外界(包括本系统当前的其它事务和来自外部系统的事务处理)修改持保守态度,通过数据库 ...

  2. java 对变量加锁_Java最全锁剖析:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁...

    乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度,在Java和数据库中都有此概念对应的实际应用. 1.乐观锁 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会 ...

  3. 【Java 并发编程】线程锁机制 ( 悲观锁 | 乐观锁 | CAS 三大问题 | ABA 问题 | 循环时间长问题 | 多个共享变量原子性问题 )

    文章目录 一.悲观锁 二.乐观锁 三.乐观锁 CAS 三大问题 一.悲观锁 假设有 222 个线程 , 线程 A 和 线程 B ; 线程 A 访问共享资源 , 线程 B 等待 , 一旦线程 A 访问结 ...

  4. Java锁详解:“独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁+线程锁”

    在Java并发场景中,会涉及到各种各样的锁如公平锁,乐观锁,悲观锁等等,这篇文章介绍各种锁的分类: 公平锁/非公平锁 可重入锁 独享锁/共享锁 乐观锁/悲观锁 分段锁 自旋锁 线程锁 乐观锁 VS 悲 ...

  5. innodb 悲观锁 乐观锁_mysql乐观锁、悲观锁、共享锁、排它锁、行锁、表锁

    mysql乐观锁.悲观锁.共享锁.排它锁.行锁.表锁 乐观锁 总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使 ...

  6. 最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁

    在Java并发场景中,会涉及到各种各样的锁,比如:高并发编程系列:4种常用Java线程锁的特点,性能比较.使用场景,这些锁有对应的种类:公平锁,乐观锁,悲观锁等等,这篇文章来详细介绍各种锁的分类: 公 ...

  7. MySQL - 行锁 表锁 乐观锁 悲观锁 读锁 写锁

    MySQL - 行锁 表锁 乐观锁 悲观锁 读锁 写锁 锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足.在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(I ...

  8. 理解悲观锁乐观锁、同步锁、读锁、写锁

    ava 锁分类 Java 中的锁有很多,可以按照不同的功能.种类进行分类,下面是我对 Java 中一些常用锁的分类,包括一些基本的概述 从线程是否需要对资源加锁可以分为 悲观锁 和 乐观锁 从资源已被 ...

  9. mysql悲观群_谈谈mysql的悲观和乐观锁

    悲观锁与乐观锁是两种常见的资源并发锁设计思路,也是并发编程中一个非常基础的概念.之前有写过一篇文章关于并发的处理思路和解决方案,这里我单独将对这两种常见的锁机制在数据库数据上的实现进行比较系统的介绍一 ...

  10. hibernate 悲观锁乐观锁

    悲观锁和乐观锁是:在事务隔离机制中设置了ReadCommited的情况下,两种可以避免不可重复读的方式. 设置成读已提交是考虑到安全和处理速度,保证并发效率,但是在这个情况下仍然需要避免不可重复读这种 ...

最新文章

  1. 数据库表DML操作不了 可能是被锁了
  2. 项目实战-阿里云域名解析设置域名
  3. Ubuntu-Python2.7安装 scipy,numpy,matplotlib
  4. linux bind命令,LINUX命令bind-系统管理-显示或设置键盘按键与其相关的功能
  5. 中国医科大学计算机应用基础本科在线作业,中国医科大学《计算机应用基础(本科)》在线作业.docx...
  6. JIRA状态为任务结束,但是解决结果为未解决相关配置
  7. javascript客户端验证函数大全
  8. 2022年认证杯SPSSPRO杯数学建模A题(第二阶段)人员的紧急疏散求解全过程文档及程序
  9. 导入从postman导出的json接口文件,并设置全局变量
  10. Js 获取浏览器高度
  11. 服务器代维护 云桥,Citrix
  12. 史上最全的launch的解析来啦,木有之一欧
  13. 面试题 猜颜色球游戏
  14. Spring Cloud Hoxton 版本微服务项目搭建 admin 监控客户端
  15. Python100道经典练习题(一)
  16. assertThat详解
  17. mysql数据库参考文献2018_reactome数据库2018更新啦
  18. Android Facebook登录,进来看就对了
  19. 带孔的打印纸怎么设置_oki打印机打印带孔纸如何缩小纸张间距
  20. http://www.dewen.net.cn/q/6120/如何获取Java对象的大小

热门文章

  1. oracle连接eclipse的包,【求助】eclipse导入了Oracle的驱动包连不上Oracle
  2. C语言 FileStreaming buffer
  3. vga/dvi/hdmi/dp
  4. docker image
  5. R语言分类算法之线性判别分析(Linear Discriminant Analysis)
  6. C/C++语言的学习策略
  7. golang | 使用结构体抄的学生信息管理系统
  8. 可靠型园区网组网,用VRRP还是堆叠?
  9. 访问控制 > 教程 > 利用标签对ECS实例进行分组授权
  10. Spring学习总结(30)——Spring事物(@transactional注解)在什么情况下会失效,为什么?