假如有两个客户端或者说是两个事务同时去修改同一条数据,就会产生并发的现象,这时候有数据的更新丢失。现在就来模拟下这个并发现象的例子:
客户端
1
或者说是事务
1
:
session.beginTransaction();
Person p = (Person)session.load(Person.class, 1);
//Person p = (Person)session.load(Person.class, 1 ,LockOptions.UPGRADE);
p.setName("士兵乙");
session.getTransaction().commit();
客户端
2
或者说是事务
2
:
session.beginTransaction();
Person p = (Person)session.load(Person.class, 1);
//Person p = (Person)session.load(Person.class, 1 ,LockOptions.UPGRADE);
p.setAddress("桃花岛");
session.getTransaction().commit();
假设现在有两个同时运行的事务:事务
1
和事务
2
两个事务,事务
1
运行到
setName
这行代码了并
setName
了修改了这个值,但是事务
1
还没有提交,这时候事务
2
也运行到了
setAddress
这行代码,但还没有执行,这时候,事务
1
提交了,巧的是事务
2
在事务
1
提交后,事务
2
它也提交了,这时候事务
1
更新的
setName
就丢失了,在显示中的客户端
1
看到自己并没有更新,还是原来的那个
Name
,而事务
2
却成功的更新了。这样前一个更新发生了丢失,即前一个事务发生了丢失。怎么解决这种并发现象呢?
1、
悲观锁定,很简单,就是在第一个客户端在加载这个对象的时候,利用数据库的能力,锁定这条记录,然后第二个客户端想要加载它改它,不让他改,直到第一个事务结束了,这时第二个客户端你才能加载修改它,即这个加载有先后,这样就控制了更新数据的丢失
Hibernate
是这样做的:
事务1:
session.beginTransaction();
Person p = (Person)session.load(Person.class, 1 ,LockOptions.UPGRADE);
Hibernate: select per0_.id as id0_0_, per0_.versionNumber as versionN2_0_0_,
per0_.name as name0_0_, per0_.address as address0_0_, per0_.qq as qq0_0_,
per0_.groupId as groupId0_0_ from t_person per0_ where per0_.id=? for
update
发出了一条数据库级别锁定一条记录的
for
update
语句,那么在事务提交之前这条记录都被锁定,因此下面第二个客户端,他上来也想修改,可是他改不了,它就停在加载对象这行代码上,不会继续往下执行,因为他在等第一个客户端提交后,他才能加载这个对象,然后修改它,这样就保证了事务的一致性
p.setName("士兵乙");
session.getTransaction().commit();
事务2:
session.beginTransaction();
Person p = (Person)session.load(Person.class, 1 ,LockOptions.UPGRADE);
也发出一条跟上面一样的for update的sql语句,但是这是的name已经是上面第一个
事务修改后的name了,这时事务再进行更新就不会有什么因并发访问而发生的更新丢
失了。
p.setAddress("桃花岛");
session.getTransaction().commit();
但是悲观锁定是针对这条记录的锁定所以并发访问比较大的话,那么会导致性能下降,一般不推荐使用
2、乐观锁定是用
Hibernate
来锁定它,而不是利用数据库的能力来维护,这个主要是通过版本控制来维护事务的。在实体中配置这个
version
标识,它必须定义在映射文件中的
id
和
property
之间,每次更新,这个
version
都会发生改变。这时候如果有两个事务同时修改这条记录,一开始他们的版本字段都是
0
,接着只要一个事务更新了这条数据,那么这个版本字段加
1
,数据库也加
1
,当第二个事务也要更新这条记录,这时候
Hibernate
会对比这个版本字段,发现版本不一致,一个是
0
,一个是
1
,接着弹出友好的提示,或抛出异常,那么你再加载一遍或
refresh
以下,这样就保证了数据的安全更新,显然这样提高了并发的性能。
<id name="id">
<generator class="native"/>
</id>
<version name="versionNumber"></version>
<property name="name"/>
事务1:
session.beginTransaction();
Person p = (Person)session.load(Person.class, 1);
p.setName("路人丙");
session.getTransaction().commit();
Hibernate: select per0_.id as id0_0_, per0_.versionNumber as
versionN2_0_0_, per0_.name as name0_0_, per0_.address as address0_0_,
per0_.qq as qq0_0_, per0_.groupId as groupId0_0_ from t_person per0_
where per0_.id=?
Hibernate: update t_person set versionNumber=?, name=?, address=?,
qq=?, groupId=? where id=? and versionNumber=?
事务2:
session.beginTransaction();
Person p = (Person)session.load(Person.class, 1);
p.setAddress("白驼山");
session.getTransaction().commit();
Hibernate: update t_person set versionNumber=?, name=?, address=?,
qq=?, groupId=? where id=? and versionNumber=?
org.hibernate.StaleObjectStateException: Row was updated or deleted by
another transaction (or unsaved-value mapping was incorrect):
[cn.com.leadfar.hibernate3.Person#1]
23:18:18,843 ERROR AbstractFlushingEventListener:324 - Could not
synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by
another transaction (or unsaved-value mapping was incorrect):
[cn.com.leadfar.hibernate3.Person#1]
分享到:
相关推荐
Hibernate高级特性,悲观锁与乐观锁的应用和区别,及两者之间的区别。
NULL 博文链接:https://12345678.iteye.com/blog/721836
Hibernate乐观锁和悲观锁分析,针对在使用HIBERNATE时怎么配置乐观锁进行了详细的范例讲解
Hibernate的乐观锁与悲观锁的文档,帮助学习Hibernate的乐观锁与悲观锁,让你们学得更轻松。
NULL 博文链接:https://cdxs2.iteye.com/blog/1938245
其中通过 version 实现的乐观锁机制是 Hibernate 官方推荐的乐观锁实现,同时也是 Hibernate 中,目前唯一在数据对象脱离 Session 发生修改的情况下依然有效的锁机制。因此,一般情况下,我们都选择 version 方式...
Hibernate锁机制_悲观锁和乐观锁
hibernate的乐观锁和悲观锁,两种锁搞定一切
主要介绍了Hibernate实现悲观锁和乐观锁的有关内容,涉及hibernate的隔离机制,以及实现悲观锁和乐观锁的代码实现,需要的朋友可以了解下。
主要介绍了Hibernate悲观锁和乐观锁实例详解,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
求助编辑百科名片相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库 性能的大量开销,特别是对长事务而言,...
NULL 博文链接:https://jordanyangwei.iteye.com/blog/313756
hibernate利用锁的相关功能详解,分为乐观锁和悲观锁。希望各位喜欢。
001 Hibernate 简介(开源 O/R 映射框架) 002 第一个 Hibernate ...025 hibernate 悲观锁、乐观锁 026 hibernate 操作树形结构 027 hibernate 查询语言(HQL) 028 hibernate 缓存(性能优化策略) 029 hibernate 抓取策略
乐观锁version 对于在Hibernate中的乐观锁和悲观锁的学习
HibernateTestHibernate乐观锁和悲观锁的学习和实践
性能------------缓存 延迟加载 事务 悲观 乐观锁
该资源主要是分析:乐观锁解决事务并发.乐观锁校验测试, 基于hiber管理的悲观锁实现