Hibernate之悲观锁与乐观锁

http://blog.csdn.net/a19881029/article/details/20665663

如果需要保证数据访问的排它性,则需对目标数据加“锁”,使其无法被其它程序修改

一,悲观锁

对数据被外界(包括本系统当前的其它事务和来自外部系统的事务处理)修改持保守态度,通过数据库提供的锁机制实现

最常用的,是对查询进行加锁(LockMode.UPGRADE和LockMode.UPGRADE_NOWAIT):

public class Test {public static void main(String[] args) {Configuration conf = new Configuration();  SessionFactory sessionFactory = conf.configure().buildSessionFactory(); Session sess = sessionFactory.openSession();Transaction tran = sess.beginTransaction();String hql = "from User where id = 1";Query query = sess.createQuery(hql);query.setLockOptions(LockOptions.UPGRADE);List<User> list = query.list();for(User user : list){System.out.print(user.getName()+" ");}System.out.println();tran.commit();sess.close(); }
}
Hibernate会在生成的SQL后面加上for update子句:

Hibernate: select user0_.id as id0_, user0_.name as name0_, user0_.age as age0_ from TEST_USER user0_ where user0_.id=1 for update
longlong 

通过for update子句,这条SQL锁定了TEST_USER表中符合检索条件的记录,本次事务提交前,外界无法修改这些记录,事务提交时会释放事务过程中的锁

Hibernate提供了2个锁对象,LockMode和LockOptions:

通过LockOptions的源代码,可以发现LockOptions只是LockMode的简单封装(在LockMode的基础上提供了timeout和scope):

......
/*** NONE represents LockMode.NONE (timeout + scope do not apply)*/
public static final LockOptions NONE = new LockOptions(LockMode.NONE);/*** READ represents LockMode.READ (timeout + scope do not apply)*/
public static final LockOptions READ = new LockOptions(LockMode.READ);/*** UPGRADE represents LockMode.UPGRADE (will wait forever for lock and* scope of false meaning only entity is locked)*/
public static final LockOptions UPGRADE = new LockOptions(LockMode.UPGRADE);public LockOptions(){}public LockOptions( LockMode lockMode) {this.lockMode = lockMode;
}
.....
public static final int NO_WAIT = 0;/*** Indicates that there is no timeout for the acquisition.* @see #getTimeOut*/
public static final int WAIT_FOREVER = -1;private int timeout = WAIT_FOREVER;private boolean scope=false;
......

LockOptions提供的加锁机制要比LockMode少很多,但是LockMode多出的加锁机制一般只是供Hibernate内部实现使用的

保证了操作的独占性,但严重影响数据库性能

二,乐观锁

乐观锁大多基于数据版本记录机制实现,既为数据增加一个版本标识

在数据库中增加version列,用来记录每行数据的版本

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" ><hibernate-mapping><class name="com.po.User" table="TEST_USER"><id name="id" column="id" type="java.lang.Integer"><generator class="assigned"/></id><version name="version"column="version"type="java.lang.Integer"/><property name="name"column="name"type="java.lang.String"not-null="true"unique="true"length="20"/><property name="age"column="age"type="java.lang.Integer"not-null="true"unique="false"length="0"/></class>
</hibernate-mapping>
每次更新User对象时时,对应行的version字段都在增加

public class Test {public static void main(String[] args) {Configuration conf = new Configuration();  SessionFactory sessionFactory = conf.configure().buildSessionFactory();Session sess1=sessionFactory.openSession();Session sess2=sessionFactory.openSession();try{User user1 = (User)sess1.get(User.class, 1);User user2 = (User)sess2.get(User.class, 1);System.out.println("v1="+user1.getVersion()+"--v2="+user2.getVersion());Transaction tx1 = sess1.beginTransaction();Transaction tx2 = sess2.beginTransaction();user1.setName("ll");tx1.commit();System.out.println("v1="+user1.getVersion()+"--v2="+user2.getVersion());user2.setName("LL");tx2.commit();}catch(Exception e){e.printStackTrace();}finally{sess1.close();sess2.close();}}
}
运行结果如下,可以看到由于tx1提交时,version字段已经被修改,tx2提交时会抛出异常:

Hibernate: select user0_.id as id0_0_, user0_.version as version0_0_, user0_.name as name0_0_, user0_.age as age0_0_ from TEST_USER user0_ where user0_.id=?
Hibernate: select user0_.id as id0_0_, user0_.version as version0_0_, user0_.name as name0_0_, user0_.age as age0_0_ from TEST_USER user0_ where user0_.id=?
v1=0--v2=0
Hibernate: update TEST_USER set version=?, name=?, age=? where id=? and version=?
v1=1--v2=0
Hibernate: update TEST_USER set version=?, name=?, age=? where id=? and version=?
Exception in thread "main" org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.po.User#1]at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1932)at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2576)at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2476)at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2803)at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:113)at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:185)at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)at com.test.Test.main(Test.java:43)
除了使用version作为版本标识,还可以使用timestamp作为版本标识

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" ><hibernate-mapping><class name="com.po.User" table="TEST_USER"><id name="id" column="id" type="java.lang.Integer"><generator class="assigned"/></id><timestamp name="updatetime"column="updatetime"/><property name="name"column="name"type="java.lang.String"not-null="true"unique="true"length="20"/><property name="age"column="age"type="java.lang.Integer"not-null="true"unique="false"length="0"/></class>
</hibernate-mapping>

在某些情况下,不允许修改数据库的表结构,此时Hibernate也有相应的处理手段:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" ><hibernate-mapping><class name="com.po.User" table="TEST_USER"optimistic-lock="all"dynamic-update="true"dynamic-insert="true"><id name="id" column="id" type="java.lang.Integer"><generator class="assigned"/></id><property name="name"column="name"type="java.lang.String"not-null="true"unique="true"length="20"/><property name="age"column="age"type="java.lang.Integer"not-null="true"unique="false"length="0"/></class>
</hibernate-mapping>

此时Hibernate将使用User类的所有字段作为版本控制信息

乐观锁相较悲观锁提高了不少性能,但是有一定的局限性,由于是在应用层加锁,如果此时在数据中直接修改数据(或其它应用程序修改数据库中的数据),应用层是无法感知到这种变化的,需要配合其它技术手段一起使用











本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/294791.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

他本硕博连跨3大专业,毕业后没多久被破格聘为985高校教授!

全世界只有3.14 % 的人关注了爆炸吧知识本文来源&#xff1a;募格学术整合自东南大学新闻网、东南大学校团委、募格课堂图片&#xff1a;网络来源&#xff1a;东南大学新闻网、东南大学校团委他从本科的计算机专业&#xff0c;到研究生的应用数学专业&#xff0c;再到博士开始研…

Winform VS2015打包

首先 &#xff0c;我们要去官网http://learn.flexerasoftware.com/content/IS-EVAL-InstallShield-Limited-Edition-Visual-Studio注册一个账号已获得installshiled的注册码。 是免费的~ 注册完后就可以下载我们的第三方打包工具&#xff1a; 注意&#xff1a;这里下载并安装完…

触发键盘_雷蛇这款光轴机械键盘开箱评测,光速触发,颜值爆表

首先感谢头条众测给予雷蛇猎魂光蛛精英版机械键盘的测评机会&#xff0c;雷蛇作为在游戏设备领域深耕的领先者&#xff0c;其生产的游戏设备深得游戏玩家喜爱&#xff0c;下面我们来一睹这款雷蛇机械键盘的风采。首先从包装盒正面可以感受到这款雷蛇光学机械轴键盘霸气侧漏&…

spring之使用Spring Security实现权限管理

转载&#xff1a;http://hanqunfeng.iteye.com/blog/1155226 目录 SpringSecurity3.X--一个简单实现 SpringSecurity3.X--前台与后台登录认证 SpringSecurity3.X--remember-me SpringSecurity3.X--验证码 作者对springsecurity研究不深&#xff0c;算是个初学者吧&#xff0c;最…

iNeuOS工业互联网操作系统,提升分布式云端控制安全策略和增加实时日志功能...

目 录1. 概述... 22. 平台演示... 23. 云端控制策略和应用过程... 23.1 云端控制策略... 23.2 控制应用过程... 34. 实时日志... 71. 概述这次升级主要提升云端控制的安全策略&#xff0c;不管公有云部署或是私有云部署&#…

直男的回答能多出乎意料?

1 我家的鸭子没这么扁&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼2 这个回答&#xff0c;妙啊...&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 强迫症犯人要求判10年▼4 像羊又像猫&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼5 美女…

Angularjs调用公共方法与共享数据

这个问题场景是在使用ionic开发页面的过程中发现&#xff0c;多个页面对应的多个controller如何去调用公共方法&#xff0c;比如给ionic引入了toast插件&#xff0c;如何将这个插件的调用变成公共方法或者设置成工具类&#xff0c;因为在每个controller中直接注入这个toast插件…

mysql去掉两个最高分_数据分析系列 16/32 | MySQL中子查询与联合查询

前面说了很多MySQL中的查询&#xff0c;比如条件查询、分组聚合查询、连接查询&#xff0c;今天来说一下另外两个非常的重要的查询&#xff0c;MySQL中的子查询和联合查询。PART01子查询子查询也称嵌套查询&#xff0c;是将一个查询语句嵌套在另一个查询语句的WHERE子句或者HAV…

那些不回你微信的人都在看什么?

如何成为一个“聊得开”的人&#xff1f;如何丰富空闲时光&#xff1f;如何在短时间内获取最最专业的文化、艺术资讯&#xff1f;小编给大家推荐几个公众号它们有趣有颜有料长按二维码&#xff0c;选择“识别图中二维码”关注印客美学id&#xff1a;inkbetter△长按二维码“识别…

按照学号查找学生_[源码和文档分享]基于JAVA和MYSQL数据库的学生成绩管理系统...

一、需求分析本系统是学生成绩管理系统&#xff0c;所以应该做到可以录入学生成绩&#xff0c;修改学生成绩&#xff0c;删除学生成绩&#xff0c;查询学生成绩&#xff0c;以及最后的所有学生按照GPA排名。本系统的数据来源期末考试成绩&#xff0c;用来实现录入&#xff0c;查…

颜宁问4对科研夫妻:男科学家怎样平衡事业家庭?

全世界只有3.14 % 的人关注了爆炸吧知识本文来源&#xff1a;科学网网上很多人一说到我&#xff0c;就说颜宁之所以能成功&#xff0c;因为她是单身&#xff0c;没有家庭拖累。但事实上&#xff0c;有家庭、有事业才是绝大多数人的现状。我们这次请来四对科研伉俪&#xff0c;不…

WebService学习笔记---CXF入门

2019独角兽企业重金招聘Python工程师标准>>> 一、准备 软件环境&#xff1a; JDK1.8, Eclipse JEE 4.4, Maven-3.2.5, Spring-4, CXF-3.1.5 二、创建项目 新建一个Maven项目&#xff0c;在pom.xml里添加spring依赖<dependencyManagement><dependencies>…

.NET 6新特性试用 | ArgumentNullException卫语句

前言在前面的文章中&#xff08;《可空引用类型》&#xff09;&#xff0c;我们介绍过编译器会帮我们检查空引用&#xff0c;但是仅仅是警告。最好的方式还是在运行时用卫语句进行检查&#xff1a;private void Test(WeatherForecast weatherForecast) {if (weatherForecast n…

JSP之EL表达式详细介绍

一、JSP EL语言定义 E L&#xff08;Expression Language&#xff09; 目的&#xff1a;为了使 JSP写起来更加简单。 表达式语言的灵感来自于 ECMAScript 和 XPath 表达式语言&#xff0c;它提供了在 JSP 中简化表达式的方法。它是一种简单的语言&#xff0c;基于可用的命名空…

那一年,爱因斯坦输得很惨很惨,被十几个诺奖得主怼了一遍后,退出了群聊……...

全世界只有3.14 % 的人关注了爆炸吧知识科学家撕逼原来这么刺激“遇事不决&#xff0c;量子力学”&#xff0c;作为长期在民间被调侃的学科&#xff0c;量子力学的名声不小&#xff0c;但它究竟有多重要&#xff0c;又是怎么来的&#xff0c;却少有人了解。而说到量子力学&…

带有帐号密码验证的apche服务器文件下载

2019独角兽企业重金招聘Python工程师标准>>> 使用python访问 #!/usr/bin/python #fileencoding:utf-8def testUrl():import urllib2import sysimport reimport base64from urlparse import urlparse#下载路径theurl http://ip/release/LHJH/Server/er_service.waru…

使用keytool查看Android APK签名

文章目录 一、找到JDK位置二、使用方法2.1 打开windows命令行工具2.2 查看签名 三、如何给APK做系统签名呢? 一、找到JDK位置 安卓AS之后&#xff0c;可选择继续安装JDK&#xff0c;如本文使用amazon版本默认位置&#xff1a;C:\Users\66176.jdks\corretto-1.8.0_342可通过自…

exchange服务器维护模式命令,Exchange服务器系列课程之七--维护邮件服务器(二)

继续上次的讨论&#xff0c;上次讨论了邮件服务器的一些监控和排错手段&#xff0c;今天我们继续来讨论邮件服务器的维护。今天主要来讨论一下邮件服务器的备份与还原。为什么要备份我就不多说了&#xff0c;备份的方法也非常简单&#xff0c;通过备份工具直接备份就可以了。这…

任务管理器在右下角的图标不显示

任务管理器在右下角的图标不显示 2012年11月7日18:22:23 症状如下图所示&#xff0c;不管是打开任务管理器还是最小化它&#xff0c;右下角均没有它的图标。 网上查到的说法均不靠谱。后来我CtrlAltDel调出任务管理器&#xff0c;找到任务管理器对应进程“taskmgr.exe”&#x…

MAUI中构建跨平台原生控件实现

简介MAUI中使用Handler体系来处理不同平台的原生控件实现, 即对应的, 如果我们想要创建控件, 只需要创建基于不同平台的Handler即可。那么下面主要教大家如何通过创建Handler(事件处理程序)来构建自己的控件。开始下面, 将通过创建一个进度条控件案例, 来演示如何在MAUI项目中创…