乐观锁的作用 柔光的暖阳◎ 2022-08-05 13:11 185阅读 0赞 乐观锁的作用 乐观锁的主要作用是为了解决事务并发带来的问题。相对于悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。 悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个"version"字段来实现。 乐观锁的工作原理 读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。 基于hibernate的乐观锁实现 基于hibernate的乐观锁实现一般有以下两种方式 * 基于version * 基于timestamp 这里就介绍一下基于version的乐观锁实现 Xml代码 [ ![复制代码][icon_copy.gif]][_icon_copy.gif] ![收藏代码][icon_star.png]![spinner.gif][] 1. **<?xml** version="1.0"**?>** 2. <!DOCTYPE hibernate-mapping PUBLIC 3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"**>** 5. **<hibernate-mapping>** 6. **<class** name="test.Dir" table="t\_dir"**>** 7. **<id** name="id" type="string" unsaved-value="null"**>** 8. **<column** name="id\_" sql-type="char(32)" not-null="true" **/>** 9. **<generator** class="uuid.hex" **/>** 10. **</id>** 11. **<version** column="version\_" name="version" **/>** 12. **<property** name="name" column="name\_" type="string"**/>** 13. **<property** name="size" column="size\_" type="long" **/>** 14. **<many-to-one** name="dir" column="pid\_" class="test.Dir" **/>** 15. **</class>** 16. **</hibernate-mapping>** <?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="test.Dir" table="t_dir"> <id name="id" type="string" unsaved-value="null"> <column name="id_" sql-type="char(32)" not-null="true" /> <generator class="uuid.hex" /> </id> <version column="version_" name="version" /> <property name="name" column="name_" type="string"/> <property name="size" column="size_" type="long" /> <many-to-one name="dir" column="pid_" class="test.Dir" /> </class> </hibernate-mapping> 这里注意version的位置,一定是要放置在id的后面 由乐观锁引发的问题 当两个不同的事务同时读取到一条数据并进行修改时,这个时候程序就会抛出org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)异常。 这里同样有两种情况 一种是两个不同的事务的情况 Java代码 [ ![复制代码][icon_copy.gif]][_icon_copy.gif] ![收藏代码][icon_star.png]![spinner.gif][] 1. @Test 2. public void testTransation1()\{ 3. Session session1 = null; 4. Session session2 = null; 5. try\{ 6. session1 = HibernateUtil.getSession(); 7. session2 = HibernateUtil.getSession(); 8. Dir dir1 = (Dir)session1.load(Dir.class, "4028811a3d3387d3013d3387d4a40008"); 9. Dir dir2 = (Dir)session2.load(Dir.class, "4028811a3d3387d3013d3387d4a40008"); 10. Transaction tx1 = session1.beginTransaction(); 11. dir1.setSize(1111); 12. tx1.commit(); 13. Transaction tx2 = session2.beginTransaction(); 14. dir2.setSize(999); 15. tx2.commit(); 16. System.out.println("事务2提交"); 17. \}catch(Exception e)\{ 18. e.printStackTrace(); 19. \}finally\{ 20. if(session1 != null)\{ 21. session1.close(); 22. \} 23. if(session2 != null)\{ 24. session2.close(); 25. \} 26. \} 27. \} @Test public void testTransation1(){ Session session1 = null; Session session2 = null; try{ session1 = HibernateUtil.getSession(); session2 = HibernateUtil.getSession(); Dir dir1 = (Dir)session1.load(Dir.class, "4028811a3d3387d3013d3387d4a40008"); Dir dir2 = (Dir)session2.load(Dir.class, "4028811a3d3387d3013d3387d4a40008"); Transaction tx1 = session1.beginTransaction(); dir1.setSize(1111); tx1.commit(); Transaction tx2 = session2.beginTransaction(); dir2.setSize(999); 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)异常 第二种情况是子事务的情况 Java代码 [ ![复制代码][icon_copy.gif]][_icon_copy.gif] ![收藏代码][icon_star.png]![spinner.gif][] 1. @Test 2. public void testTransation5()\{ 3. Session session1 = null; 4. Session session2 = null; 5. try\{ 6. session1 = HibernateUtil.getSession(); 7. session2 = HibernateUtil.getSession(); 8. Dir dir1 = (Dir)session1.load(Dir.class, "4028811a3d3387d3013d3387d4a40008"); 9. Dir dir2 = (Dir)session2.load(Dir.class, "4028811a3d3387d3013d3387d4a40008"); 10. Transaction tx1 = session1.beginTransaction(); 11. Transaction tx2 = session2.beginTransaction(); 12. dir2.setSize(7777); 13. tx2.commit(); 14. dir1.setSize(3333); 15. tx1.commit(); 16. \}catch(Exception e)\{ 17. e.printStackTrace(); 18. \}finally\{ 19. if(session1 != null)\{ 20. session1.close(); 21. \} 22. if(session2 != null)\{ 23. session2.close(); 24. \} 25. \} 26. \} @Test public void testTransation5(){ Session session1 = null; Session session2 = null; try{ session1 = HibernateUtil.getSession(); session2 = HibernateUtil.getSession(); Dir dir1 = (Dir)session1.load(Dir.class, "4028811a3d3387d3013d3387d4a40008"); Dir dir2 = (Dir)session2.load(Dir.class, "4028811a3d3387d3013d3387d4a40008"); Transaction tx1 = session1.beginTransaction(); Transaction tx2 = session2.beginTransaction(); dir2.setSize(7777); tx2.commit(); dir1.setSize(3333); 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、尽量从业务方面去减小事务块,事务块越大,由乐观锁引起的问题的概率就越大 [icon_copy.gif]: http://skyuck.iteye.com/images/icon_copy.gif [_icon_copy.gif]: http://skyuck.iteye.com/blog/1833099# [icon_star.png]: http://skyuck.iteye.com/images/icon_star.png [spinner.gif]: /images/20220805/a0020a8c9bd0433f8c1d3745d9f56e24.png
相关 乐观锁、悲观锁 乐观锁、悲观锁 基本概念 实现方式 优缺点和适用场景 基本概念 乐观锁和悲观锁是两种思想,用于解决并发场景下的数据竞争问题。 乐观锁:乐 落日映苍穹つ/ 2023年10月05日 19:33/ 0 赞/ 51 阅读
相关 乐观锁 在并发访问情况下,可能会出现脏读、不可重复读和幻读等读现象,为了应对这些问题,主流数据库都提供了锁机制,并引入了事务隔离级别的概念。数据库管理系统(DBMS)中的并发控制 柔光的暖阳◎/ 2022年12月27日 09:23/ 0 赞/ 134 阅读
相关 乐观锁 乐观锁 (一)什么是乐观锁 乐观锁是为了解决线程冲突情况下脏读,幻读等,乐观锁就是为了解决这个问题而产生的;乐观锁默认情况下认为数据是不会发生冲突的,所以在数据进行 清疚/ 2022年11月05日 03:30/ 0 赞/ 206 阅读
相关 悲观锁乐观锁 悲观锁/乐观锁 悲观锁 悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别的线程会修改,所以每 次在拿数据的时候都会上锁。Java中synchronized和 秒速五厘米/ 2022年09月11日 11:08/ 0 赞/ 279 阅读
相关 数据库设置乐观锁--作用 Hibernate支持乐观锁。当多个事务同时对数据库表中的同一条数据操作时,如果没有加锁机制的话,就会产生脏数据(duty data)。Hibernate有2种机制可以解决这个 灰太狼/ 2022年08月19日 04:58/ 0 赞/ 111 阅读
相关 乐观锁的作用 乐观锁的作用 乐观锁的主要作用是为了解决事务并发带来的问题。相对于悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。 悲观锁大多数情况下依靠数据库的锁 柔光的暖阳◎/ 2022年08月05日 13:11/ 0 赞/ 186 阅读
相关 乐观锁 乐观锁一般是在数据库的记录中添加一个版本号的冗余字段。 此图可以辅助理解乐观锁的使用。本图来自曾经浏览的某篇文章,具体地址忘记了,因此没有标注来源,只能用文字说明下 ! 本是古典 何须时尚/ 2022年06月13日 08:42/ 0 赞/ 218 阅读
相关 乐观锁 乐观锁 听这个名字就会想到一个叫做悲观锁。传统的锁那就是悲观锁(自己使用时别人就用不了),而对于悲观锁,乐观锁的特点是别人都能查看到信息,只是修改的时候需要拿到版本号去比对 £神魔★判官ぃ/ 2022年06月12日 13:49/ 0 赞/ 212 阅读
相关 乐观锁悲观锁 悲观锁(Pessimistic Lock)顾名思义,就是很悲观,每次获取数据的时候都认为会修改数据,因此每次在获取数据的时候都会对此条数据进行锁定,也就是mysql数据库的行锁 我就是我/ 2022年06月11日 00:12/ 0 赞/ 303 阅读
相关 乐观锁 在高并发的情况下,数据在update时可能会溢出。就是超出你想要的一个范围。我们可以使用乐观锁来解决。 添加一个verison字段,把verison查出来,比如我查出来当前 偏执的太偏执、/ 2022年05月27日 07:29/ 0 赞/ 225 阅读
还没有评论,来说两句吧...