【Hibernate】Hibernate对“悲观”和“乐观”锁的支持

2024-08-26 21:18
文章标签 hibernate 悲观 乐观 支持

本文主要是介绍【Hibernate】Hibernate对“悲观”和“乐观”锁的支持,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

          首先,“锁”这个东西,可以认为是一种思想,悲观锁还是乐观锁,是人定义出来的一种概念,并非理解为DBMS的专属。换个称呼,叫做“悲观并发控制”或者“乐观并发控制”更便于我们理解二者的意义。

        

一、概念

       ----(该部分内容来源于网络:http://www.open-open.com/lib/view/open1452046967245.html)----

       悲观锁:

       在关系数据库管理系统里,悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)是一种并发控制的方法。它可以阻止一个事务以影响其他用户的方式来修改数据。如果一个事务执行的操作都某行数据应用了锁,那只有当这个事务把锁释放,其他事务才能够执行与该锁冲突的操作。悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。
       悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度(悲观),因此,在整个数据处理过程中,将数据处于锁定状态。 悲观锁的实现,往往依靠数据库提供的锁机制 (也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)


       乐观锁:

       在关系数据库管理系统里,乐观并发控制(又名“乐观锁”,Optimistic Concurrency Control,缩写“OCC”)是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,正在提交的事务会进行回滚。乐观事务控制最早是由孔祥重(H.T.Kung)教授提出。
       乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。
       相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。

           ---------------------------------------------------------------------------------------------------


二、实例分析

        如图所示:

        

           两个人分别从1000里取出200,A本该剩余800,B本该剩余600,观察上图,A剩余了800,同时B也剩余了800。问题就出在A取出的同时,B也去取,导致被减数读错。

               

        如图所示,此时方为正解,既然了解了悲观锁和乐观锁的特性,就分别来实现他们。


三、代码实现

      一、悲观锁

    (1)实体类

public class Inventory {//编号private String itemNo;//名称private String itemName;//数量private int quantity;public String getItemName() {return itemName;}public void setItemName(String itemName) {this.itemName = itemName;}public String getItemNo() {return itemNo;}public void setItemNo(String itemNo) {this.itemNo = itemNo;}public int getQuantity() {return quantity;}public void setQuantity(int quantity) {this.quantity = quantity;}
}

     (2)单元测试

       测试方法一:模拟操作员A取奶粉

public void testLoad1() {Session session = null;try {session = HibernateUtils.getSession();session.beginTransaction();//使用锁的模式为“悲观锁” Inventory inv = (Inventory)session.load(Inventory.class, "1001", LockMode.UPGRADE); //使用LockMode.UPGRADE,悲观锁的应用类型System.out.println("opt1-->itemNo=" + inv.getItemNo());System.out.println("opt1-->itemName=" + inv.getItemName());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);}
}

      测试方法二:模拟B操作员取奶粉

public void testLoad2() {Session session = null;try {session = HibernateUtils.getSession();session.beginTransaction();Inventory inv = (Inventory)session.load(Inventory.class, "1001", LockMode.UPGRADE); //System.out.println("opt2-->itemNo=" + inv.getItemNo());System.out.println("opt2-->itemName=" + inv.getItemName());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);}
}	
       通过在加载Inventory的Load方法中使用:LockMode.UPGRADE,标注加载过程执行了“悲观锁”,使得在执行testLoad1的时候,锁定了“1001”行记录(因为在select * for update中,锁级别是“行级锁”),只有在testLoad1()的事务提交之后,才进行testLoad2()的执行。

       至此,保证了A和B分别能够拿到“800”和“600”的执行结果。


       二、乐观锁

      (1)实体类,同上

      (2)在hbm.xml配置文件中(hibernate的映射文件)

<class name="" table="" optimistic-lock="version">
       加入对乐观锁的属性“optimistic-lock”,并绑定“version”字段。

      (3)单元测试

       测试方法一:模拟A的取奶粉操作

public void testLoad1() {Session session = null;try {session = HibernateUtils.getSession();session.beginTransaction();Inventory inv = (Inventory)session.load(Inventory.class, "1001"); //去掉了optimistic-lock属性配置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);}
}
         测试方法二:模拟B的取奶粉操作

public void testLoad2() {Session session = null;try {session = HibernateUtils.getSession();session.beginTransaction();Inventory inv = (Inventory)session.load(Inventory.class, "1001");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);}
}	

          对比“悲观锁”和“乐观锁”,于Hibernate的实现,load方法加载过程不一样,前者通过LockMode.UPGRADE加以限制,后者则是在hbm.xml中,通过class标签加以限制。

      初次接触Hibernate对并发的控制,不足之处,请多多指教!


       




这篇关于【Hibernate】Hibernate对“悲观”和“乐观”锁的支持的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1109700

相关文章

java面试常见问题之Hibernate总结

1  Hibernate的检索方式 Ø  导航对象图检索(根据已经加载的对象,导航到其他对象。) Ø  OID检索(按照对象的OID来检索对象。) Ø  HQL检索(使用面向对象的HQL查询语言。) Ø  QBC检索(使用QBC(Qurey By Criteria)API来检索对象。 QBC/QBE离线/在线) Ø  本地SQL检索(使用本地数据库的SQL查询语句。) 包括Hibern

Golang支持平滑升级的HTTP服务

前段时间用Golang在做一个HTTP的接口,因编译型语言的特性,修改了代码需要重新编译可执行文件,关闭正在运行的老程序,并启动新程序。对于访问量较大的面向用户的产品,关闭、重启的过程中势必会出现无法访问的情况,从而影响用户体验。 使用Golang的系统包开发HTTP服务,是无法支持平滑升级(优雅重启)的,本文将探讨如何解决该问题。 一、平滑升级(优雅重启)的一般思路 一般情况下,要实现平滑

org.hibernate.hql.ast.QuerySyntaxException:is not mapped 异常总结

org.hibernate.hql.ast.QuerySyntaxException: User is not mapped [select u from User u where u.userName=:userName and u.password=:password] 上面的异常的抛出主要有几个方面:1、最容易想到的,就是你的from是实体类而不是表名,这个应该大家都知道,注意

Caused by: org.hibernate.MappingException: Could not determine type for: org.cgh.ssh.pojo.GoodsType,

MappingException:这个主要是类映射上的异常,Could not determine type for: org.cgh.ssh.pojo.GoodsType,这句话表示GoodsType这个类没有被映射到

Hibernate框架中,使用JDBC语法

/*** 调用存储过程* * @param PRONAME* @return*/public CallableStatement citePro(final String PRONAME){Session session = getCurrentSession();CallableStatement pro = session.doReturningWork(new ReturningWork<C

hibernate修改数据库已有的对象【简化操作】

陈科肇 直接上代码: /*** 更新新的数据并并未修改旧的数据* @param oldEntity 数据库存在的实体* @param newEntity 更改后的实体* @throws IllegalAccessException * @throws IllegalArgumentException */public void updateNew(T oldEntity,T newEntity

sqlite不支持中文排序,采用java排序

方式一 不支持含有重复字段进行排序 /*** sqlite不支持中文排序,改用java排序* 根据指定的对象属性字段,排序对象集合,顺序* @param list* @param field* @return*/public static List sortListByField(List<?> list,String field){List temp = new ArrayList(

一款支持同一个屏幕界面同时播放多个视频的视频播放软件

GridPlayer 是一款基于 VLC 的免费开源跨平台多视频同步播放工具,支持在一块屏幕上同时播放多个视频。其主要功能包括: 多视频播放:用户可以在一个窗口中同时播放任意数量的视频,数量仅受硬件性能限制。支持多种格式和流媒体:GridPlayer 支持所有由 VLC 支持的视频格式以及流媒体 URL(如 m3u8 链接)。自定义网格布局:用户可以配置播放器的网格布局,以适应不同的观看需求。硬

Science Robotics 首尔国立大学研究团队推出BBEX外骨骼,实现多维力量支持!

重复性举起物体可能会对脊柱和背部肌肉造成损伤,由此引发的腰椎损伤是工业环境等工作场所中一个普遍且令人关注的问题。为了减轻这类伤害,有研究人员已经研发出在举起任务中为工人提供辅助的背部支撑装置。然而,现有的这类装置通常无法在非对称性的举重过程中提供多维度的力量支持。此外,针对整个人体脊柱的设备安全性验证也一直是一个缺失的环节。 据探索前沿科技边界,传递前沿科技成果的X-robot投稿,来自首尔国立

超级 密码加密 解密 源码,支持表情,符号,数字,字母,加密

超级 密码加密 解密 源码,支持表情,符号,数字,字母,加密 可以将表情,动物,水果,表情,手势,猫语,兽语,狗语,爱语,符号,数字,字母,加密和解密 可以将文字、字母、数字、代码、标点符号等内容转换成新的文字形式,通过简单的文字以不同的排列顺序来表达不同的内容 源码截图: https://www.httple.net/152649.html