【Hibernate 9】悲观锁和乐观锁
一、锁的基本简介
1.1,为什么需要锁
首先,锁的概念产生,主要是为了解决并发性的问题。什么是并发性问题呢,比如:
Angel现在银行有个账号,里面有存款1000块。现在,Angel的账户,在两个地方分别执行操作。首先,Angel妈妈拿着主卡在四川给Angel账户存钱,读取出Angel的余额是1000块。其次,Angel拿着副卡在廊坊从账户里取钱,读取出angel 的余额是1000块。这时候,angel取了200块钱,余额变为1000-200=800块。可是angel妈妈执行存钱1000块操作,Angel余额变为1000+1000=2000(Angel妈妈最初读取出的余额为1000)这时候,Angel的余额就出现了问题,按照正常逻辑,账户余额为1000-200+1000=1800块。这个问题,就叫做更新丢失。Angel的账户,丢失了取款200的更新。为了解决这一个问题,我们需要引入锁的概念
1.2,悲观锁
悲观锁:通常是有数据库机制实现的,在整个过程中把数据锁住(查询),只要事务不释放(提交 / 回滚),那么任何用户都不能查看或修改。
正如上面的例子,Angel妈妈在四川,读取出了Angel的余额,那么angel的账户就被锁定了。angel就不能在廊坊对其账户进行操作,只有等到angel妈妈对这个账户的更新结束,也就是正常更新余额1000+1000=2000的业务结束,angel才能在廊坊执行取款操作。那么,悲观锁对外界的修改持保守态度,有效的保证了数据的一致性。但是,优点:它不适合多个用户并发访问。当一个锁住的资源不被释放掉的时候,这个资源永远不会被其他用户进行修改,容易造成无限期的等待,也就是等待超时。(想象一下,angel妈妈一直没有执行完存钱操作,angel取钱的道路该是多么的艰辛。。。或者说angel一直没有执行完取钱操作,angel妈妈的存钱道路该有多么心酸。。。)
那么,怎样能保证数据的一致性,又不会导致无期限的等待呢?
1.3,乐观锁
乐观锁,从本质上来说并不是一种锁,它大多数的使用是采用数据版本的方式(version)实现,一般在数据库中加入一个version字段,在读取数据的时候将version读取出来,在保存数据的时候判断version的值是否小于数据库中的version值,如果小于不予更新,否则给予更新。
如果运用乐观锁的实现机制去解决Angel的取款问题,则会发生什么呢?首先,angel妈妈在四川读出angel的余额1000,和其数据的版本号1;同时angel在廊坊也读取出了余额1000,和版本号1。这时候angel执行了取款操作200,更新余额为1000-200=800,同时将数据版本号更新为2。这时候angel妈妈执行存钱操作,而版本号1<2,所以不予以执行1000+1000=2000的更新操作。若是要存款,只能再次执行业务流程,这样,保证了数据的一致性。
1.4,Hibernate的加锁模式
A: LockMode.NONE : 无锁机制。
B:LockMode.WRITE : Hibernate 在 Insert 和 Update 记录的时候会自动获取。
C:LockMode.READ : Hibernate 在读取记录的时候会自动获取。
以上这三种锁机制一般由 Hibernate 内部使用,如 Hibernate 为了保证 Update过程中对象不会被外界修改,会在 save 方法实现中自动为目标对象加上 WRITE 锁。
D: LockMode.UPGRADE :利用数据库的 for update 子句加锁。
E: LockMode. UPGRADE_NOWAIT : Oracle 的特定实现,利用 Oracle 的 for update nowait 子句实现加锁。
二、实例分析Hibernate的锁机制
2.1,乐观锁
<span style="font-family:KaiTi_GB2312;font-size:18px;"><?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.angel.hibernate.Inventory" table="t_inventory" <span style="color:#ff0000;">optimistic-lock="version"</span>>
<id name="itemNo">
<generator class="assigned"/>
</id>
<version name="version"/>
<property name="itemName"/>
<property name="quantity"/>
</class>
</hibernate-mapping></span>
测试类:
<span style="font-family:KaiTi_GB2312;font-size:18px;">package test.com.angel.hibernate; import junit.framework.TestCase; import org.hibernate.Session; import com.angel.hibernate.HibernateUtils;
import com.angel.hibernate.Inventory; public class OptimisticLockingTest extends TestCase { public void testLoad1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Inventory inv = (Inventory) session.load(Inventory.class, "1002");
System.out.println("opt1-->itemNo=" + inv.getItemNo());
System.out.println("opt1-->itemName=" + inv.getItemName());
System.out.println("opt1-->version=" + inv.getVersion());
System.out.println("opt1-->quantity=" + inv.getQuantity()); inv.setQuantity(inv.getQuantity() - 200); session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
HibernateUtils.closeSession(session);
}
} public void testLoad2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Inventory inv = (Inventory) session.load(Inventory.class, "1002");
System.out.println("opt2-->itemNo=" + inv.getItemNo());
System.out.println("opt2-->itemName=" + inv.getItemName());
System.out.println("opt2-->version=" + inv.getVersion());
System.out.println("opt2-->quantity=" + inv.getQuantity()); inv.setQuantity(inv.getQuantity() + 200); session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
HibernateUtils.closeSession(session);
}
} }
</span>
当我们在方法1读取数据结束,但是未提交事务之前,紧接着执行方法2的时候,由于version字段的值被更改,所以会导致方法1执行不通过,从而保证了数据的一致性。
2.2,悲观锁
<span style="font-family:KaiTi_GB2312;font-size:18px;">package test.com.angel.hibernate; import junit.framework.TestCase; import org.hibernate.LockMode;
import org.hibernate.Session; import com.angel.hibernate.HibernateUtils;
import com.angel.hibernate.Inventory; public class OptimisticLockingTest extends TestCase { public void testLoad1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Inventory inv = (Inventory) session.load(Inventory.class, "1002",LockMode.UPGRADE);
System.out.println("opt1-->itemNo=" + inv.getItemNo());
System.out.println("opt1-->itemName=" + inv.getItemName());
System.out.println("opt1-->version=" + inv.getVersion());
System.out.println("opt1-->quantity=" + inv.getQuantity()); inv.setQuantity(inv.getQuantity() - 200); session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
HibernateUtils.closeSession(session);
}
} public void testLoad2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Inventory inv = (Inventory) session.load(Inventory.class, "1002",LockMode.UPGRADE);
System.out.println("opt2-->itemNo=" + inv.getItemNo());
System.out.println("opt2-->itemName=" + inv.getItemName());
System.out.println("opt2-->version=" + inv.getVersion());
System.out.println("opt2-->quantity=" + inv.getQuantity()); inv.setQuantity(inv.getQuantity() + 200); session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
HibernateUtils.closeSession(session);
}
} }
</span>
当我们在方法1读取数据结束,但是未提交事务之前,紧接着执行方法2的时候,由于添加悲观锁的缘故,方法2无法执行,只有当方法1进行了提交,方法2才能继续执行。
三、总结
加锁可以有效的解决并发问题,但是,这也得根据应用程序的具体情况而定。如果开发 的应用程序都是单人操作,那么根本就不必引入锁的概念。在这里,顺便总结一下数据中锁的基本分类:
共享 (S) 用于不更改或不更新数据的操作(只读操作),如 SELECT 语句。
更新 (U) 用于可更新的资源中。防止当多个会话在读取、锁定以及随后可能进行的资源更新时发生常见形式的死锁。
排它 (X) 用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。确保不会同时同一资源进行多重更新。
【Hibernate 9】悲观锁和乐观锁的更多相关文章
- Hibernate解决高并发问题之:悲观锁 VS 乐观锁
高并发问题是程序设计所必须要解决的问题,解决此类问题最主要的途径就是对对程序进行加锁控制.hibernate对加锁机制同样做出了实现,常用加锁方式为悲观锁和乐观锁.悲观锁指的是对数据被外界(包括本系统 ...
- 025 hibernate悲观锁、乐观锁
Hibernate谈到悲观锁.乐观锁,就要谈到数据库的并发问题,数据库的隔离级别越高它的并发性就越差 并发性:当前系统进行了序列化后,当前读取数据后,别人查询不了,看不了.称为并发性不好 数据库隔离级 ...
- Hibernate 再接触 悲观锁和乐观锁
为什么取1248 二进制 CRUD 移位效率高 在并发和效率选择一个平衡点 一般不会考虑幻读 因为我们不会再一个事务里查询两次,(只能设置为seralizable) 悲观锁和乐观锁的前提是read-u ...
- Hibernate的悲观锁和乐观锁
前一篇博客我们从数据库角度分析,锁可以分为三种,分别为共享锁,独占锁和更新锁.我们从程序的角度来看锁可以分为两种类型,悲观锁和乐观锁,Hibernate提供对这两种锁 的支持,我们来了解一下Hiber ...
- mysql-mysql悲观锁和乐观锁
1.mysql的四种事务隔离级别 I. 对于同时运行多个事务,当这些事务访问数据库中的相同数据时,如果没有采取必要的隔离机制,就会导致各种并发问题. (1)脏读: 对于两个事物 T1, T2, T1 ...
- Oracle数据库悲观锁与乐观锁详解
数据的锁定分为两种方法,第一种叫做悲观锁,第二种叫做乐观锁.什么叫悲观锁呢,悲观锁顾名思义,就是对数据的冲突采取一种悲观的态度,也就是说假设数据肯定会冲突,所以在数据开始读取的时候就把数据锁定住.而乐 ...
- MySQL学习笔记(四)悲观锁与乐观锁
恼骚 最近在搞并发的问题,订单的异步通知和主动查询会存在并发的问题,用到了Mysql数据库的 for update 锁 在TP5直接通过lock(true),用于数据库的锁机制 Db::name('p ...
- 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景?
在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种 ...
- Oracle的悲观锁和乐观锁
为了得到最大的性能,一般数据库都有并发机制,不过带来的问题就是数据访问的冲突.为了解决这个问题,大多数数据库用的方法就是数据的锁定. 数据的锁定分为两种方法,第一种叫做悲观锁,第二种叫做乐观锁.什么叫 ...
- (转载)Oracle的悲观锁和乐观锁
为了得到最大的性能,一般数据库都有并发机制,不过带来的问题就是数据访问的冲突.为了解决这个问题,大多数数据库用的方法就是数据的锁定. 数据的锁定分为两种方法,第一种叫做悲观锁,第二种叫做乐观锁.什么叫 ...
随机推荐
- SpringMVC4.0.3 @ResponseBody JSON 中文乱码问题
@RequestMapping(value="listUserJson.html",produces="text/html;charset=UTF-8") @R ...
- Spark工程开发前台技术实现与后台函数调用
Spark是一个通用的大规模数据快速处理引擎.可以简单理解为Spark就是一个大数据分布式处理框架.基于内存计算的Spark的计算速度要比Hadoop的MapReduce快上50倍以上,基于磁盘的计算 ...
- DBA_Oracle海量数据处理分析(方法论)
2014-12-18 Created By BaoXinjian
- Altiium Designer 09 解决局域网冲突的办法(转载)
Altiium Designer 09 解决局域网冲突的办法(转载) 一 通过防护墙禁止进程访问网络: 1.1打开DXP.EXE,然后在360的流量防护墙或WINDOWS防护墙禁止该进程访问网络.注意 ...
- window下安装oracle数据库
Oracle 11g安装 1.解压下载的包,然后进入包内,点击setup.exe开始安装 . 2.出现如下:一般把那个小对勾取消,点击下一步进行, 弹出下图这个后点‘是’ 3.下图后,选择创建和配置数 ...
- ethereal抓包工具
ethereal是目前网络上开源的一款功能强大的以太网抓包工具,该软件可以监听异常封包,检测软件封包问题,从网络上抓包,并且能对数据包进行分析,从而帮助用户解决各种网络故障,更加方便查看.监控TCP ...
- C++学习13 类class和结构体struct的区别
C++保留了C语言的 struct,并且加以扩充.在C语言中,struct 只能包含数据成员,不能包含成员函数.而在C++中,struct 类似于 class,既可以包含数据成员,又可以包含成员函数. ...
- crm plugin 未能加载文件或程序集“xxxx,”或它的某一个依赖项。系统找不到指定的文件。
plugin运行出错. 1 plugin文件如果是 注册到disk,应该是注册到 C:\Program Files\Microsoft Dynamics CRM\Server\bin\assembl ...
- bat文件创建mysql数据库 数据库名为meter
-- 详见附件,已自测通过 //修改为mysql安装路径 C:\Program Files\MySQL\MySQL Server 5.5" createtestd ...
- springMVC整合spring和hibernate4(适合于框架的搭建)
基础的东西不再详细说明,只在这里说明一下主要的配置文件,如何通过配置文件取得sessionFactory . 步骤: 1:在web.xml中引入springmvc的配置文件springmvc.xml( ...