hibernate悲观锁,乐观锁
业务逻辑的实现过程中,往往需要保证数据访问的排他性。因此,我们就需要通过一些机制来保证这些数据在某个操作过程中不会被外界修改,这样的机制,在这里,也就是所谓的“锁”,即给我们选定的目标数据上锁,使其无法被其它程序修改。
Hibernate 支持两种锁机制:
1. 悲观锁(Pessimistic Locking)
从加载对象就开始锁定。修改过程中一直是锁。直到事务commit()提交后再解锁。
session.load(Info.class,"p003",LockOptions.UPGRADE);

- public class TestPessimisticLock extends TestCase {
- @Test
- public 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();
- }
- }
- @Test
- public 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和setter
- public 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、尽量从业务方面去减小事务块,事务块越大,由乐观锁引起的问题的概率就越大
hibernate悲观锁,乐观锁的更多相关文章
- Hibernate悲观锁/乐观锁
如果需要保证数据访问的排它性,则需对目标数据加"锁",使其无法被其它程序修改 一,悲观锁 对数据被外界(包括本系统当前的其它事务和来自外部系统的事务处理)修改持保守态度,通过数据库 ...
- Java并发 行级锁/字段锁/表级锁 乐观锁/悲观锁 共享锁/排他锁 死锁
原文地址:https://my.oschina.net/oosc/blog/1620279 前言 锁是防止在两个事务操作同一个数据源(表或行)时交互破坏数据的一种机制. 数据库采用封锁技术保证并发操作 ...
- Optimistic concurrency control 死锁 悲观锁 乐观锁 自旋锁
Optimistic concurrency control https://en.wikipedia.org/wiki/Optimistic_concurrency_control Optimist ...
- SQL Server 锁机制 悲观锁 乐观锁 实测解析
先引入一些概念,直接Copy其他Blogs中的,我就不单独写了. 一.为什么会有锁 多个用户同时对数据库的并发操作时会带来以下数据不一致的问题: 1.丢失更新 A,B两个用户读同一数据并进行修改,其中 ...
- 最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁
在Java并发场景中,会涉及到各种各样的锁如公平锁,乐观锁,悲观锁等等,这篇文章介绍各种锁的分类: 公平锁/非公平锁 可重入锁 独享锁/共享锁 乐观锁/悲观锁 分段锁 自旋锁 01.乐观锁 vs 悲观 ...
- Java最全锁剖析:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁
乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度,在Java和数据库中都有此概念对应的实际应用. 1.乐观锁 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会 ...
- Hibernate 悲观锁,乐观锁
业务逻辑的实现过程中,往往需要保证数据访问的排他性.因此,我们就需要通过一些机制来保证这些数据在某个操作过程中不会被外界修改,这样的机制,在这里,也就是所谓的“锁”,即给我们选定的目标数据上锁,使其无 ...
- hibernate 悲观锁乐观锁
悲观锁和乐观锁是:在事务隔离机制中设置了ReadCommited的情况下,两种可以避免不可重复读的方式. 设置成读已提交是考虑到安全和处理速度,保证并发效率,但是在这个情况下仍然需要避免不可重复读 ...
- 【MySQL】悲观锁&乐观锁
悲观锁与乐观锁是两种常见的资源并发锁设计思路,也是并发编程中一个非常基础的概念.本文将对这两种常见的锁机制在数据库数据上的实现进行比较系统的介绍. 悲观锁(Pessimistic Lock) 悲观锁的 ...
- innodb 悲观锁,乐观锁
转 http://www.cnblogs.com/chenwenbiao/archive/2012/06/06/2537508.html CREATE TABLE `products` ( `id` ...
随机推荐
- hihoCoder #1050 : 树中的最长路
题意: 求出树上最长路径的长度,并返回. 思路: 刚看到数据<=10^5,假如是单分支的树,那么有5万层,就不能递归,那就用桟实现, 那就要将长度信息保存在另开的数组中,很麻烦!!这题专门给递归 ...
- WebClient UI和Tomcat的启动器
WebClient UI 我们在WebClient UI的开发工具里点了Test按钮, 会在浏览器以测试模式打开选中的view.这背后发生了什么事?注意浏览器地址栏的bspwd_cmp_test,这是 ...
- CDOJ 485 UESTC 485 Game (八数码变形,映射,逆cantor展开)
题意:八数码,但是转移的方式是转动,一共十二种,有多组询问,初态唯一,终态不唯一. 题解:初态唯一,那么可以预处理出012345678的所有转移情况,然后将初态对012345678做一个映射,再枚举一 ...
- 使用FileSystemWatcher组件监视日志文件
实现效果: 知识运用: FileSystemWatcher组件的Path属性 Filter属性 //要监视那些文件 默认为*.* Endinit方法 //结束在窗体上使用或有另一个组件使用的Fil ...
- OO第三次电梯作业优化
目录 第三次电梯作业个人优化 前言 优化思路 一.调度器 二.电梯 第三次电梯作业个人优化 前言 由于个人能力有限,第二次电梯作业只能完成正确性设计,没能进行优化,也因此损失了强测分数,于是第三次电梯 ...
- vector 下标操作
比如:vector<int> ivec(3).. 当采用下标操作ivec[10]的时候,该操作是未定义的,在自己的机器上输出的值是零.建议使用迭代器进行操作.
- javaweb基础(16)_jsp指令
一.JSP指令简介 JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分. 在JSP 2.0规范中共定义了三个指令: pa ...
- java基础—数组
一.数组的基本概念 数组可以看成是多个相同类型数据组合,对这些数据的统一管理. 数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量. 数组的元素可以是任何数据类型,包括基 ...
- 【Ubuntu】ubuntu基本操作命令
本文主要是用于记录ubuntu中会使用到的命令,但是有不是特别常用的,用于自己后续查阅使用. 1.查询ubuntu版本信息 方法一: cat /etc/issue 方法二: sudo lsb_rele ...
- Python入门:Python基础笔记
(C语言:)C语言是相对C++.C#.Java等语言更接近底层,并且一些硬件编程都可以使(只能使用)C语言.另外C语言学起来相对困难,因为涉及到指针,指针也是语言接近底层语言的一个特征.目前编写较大的 ...