Hibernate的悲观锁、乐观锁
来源:互联网 发布:郝斌老师c语言笔记 编辑:程序博客网 时间:2024/05/21 09:33
多个用户同时访问一个数据库,则当他们的事务同时使用相
同的数据时可能会发生问题。由于并发操作带来的数据不一致性包括:丢失数据
修改、读
”
脏
”
数据(脏读)、不可重复读、产生幽灵数据
多个用户同时访问一个数据库,当他们的事务同时使用相同的数据时可能会发生问题。由于并发操作带来的数据不一致性包括丢失数据、修改、脏读、不可重复读、产生幽灵数据。为了解决并发问题hibernate提出了悲观锁和乐观锁来解决问题。
悲观锁
新建一个java项目,项目结构如下
User类
public class User {private int id;private String name;private String pwd;//省略get/set}
User.hbm.xml配置
<hibernate-mapping package="com.test.pojo"> <class name="User" table="user"> <id name="id"> <generator class="identity" /> </id> <property name="name" /> <property name="pwd" /> </class> </hibernate-mapping>HIbernateTest
public class HibernateTest {@Testpublic void testCreateDB(){Configuration cfg=new Configuration().configure();SchemaExport se=new SchemaExport(cfg);se.create(true, true);}@Testpublic void testSave(){Session session=HibernateUtil.getSession();Transaction tx=session.beginTransaction();User user=new User();user.setName("张三");user.setPwd("1111");session.save(user);tx.commit();HibernateUtil.closeSession();}@Testpublic void testGet(){Session session=HibernateUtil.getSession();Transaction tx=session.beginTransaction();User user=(User) session.get(User.class, 1, LockOptions.UPGRADE);System.out.println(user.getName());user.setName("李四");session.update(user);tx.commit();HibernateUtil.closeSession();}@Testpublic void testGet1(){Session session=HibernateUtil.getSession();Transaction tx=session.beginTransaction();User user=(User) session.get(User.class, 1,LockOptions.UPGRADE);System.out.println(user.getName());user.setName("李四");session.update(user);tx.commit();HibernateUtil.closeSession();}}上面代码中testGet和testGet1是两个测试悲观锁的方法,有两个session,如果同时启动,就相当于同时有两个线程启动,当第一个session执行了
User user=(User) session.get(User.class, 1, LockOptions.UPGRADE);这句代码,后面的线程需要等待,直到这个session关闭之后,其他线程才能继续执行,以此类推。
乐观锁
乐观锁和悲观锁不同的是,乐观锁不是排他性,而是使用了一个版本version来记录,当数据被更改后,version会更改。
新建java项目,项目结构如下:
User代码
public class User {private int id;private String name;private String pwd;private int version;//省略get/set}User.hbm.xml配置
<hibernate-mapping package="com.test.pojo"> <class name="User" table="user"> <id name="id"> <generator class="identity" /> </id> <version name="version"/> <property name="name" /> <property name="pwd" /> </class> </hibernate-mapping>
HibernateTest测试代码
public class HibernateTest {@Testpublic void testCreateDB(){Configuration cfg=new Configuration().configure();SchemaExport se=new SchemaExport(cfg);se.create(true, true);}@Testpublic void testSave(){Session session=HibernateUtil.getSession();Transaction tx=session.beginTransaction();User user=new User();user.setName("张三");user.setPwd("1111");session.save(user);tx.commit();HibernateUtil.closeSession();}@Testpublic void testGet(){Session session = null; Transaction tx = null; User user = null; try { session = HibernateUtil.getSession(); tx = session.beginTransaction(); user = (User) session.get(User.class, 1) ; user.setName("李四") ; Session session1 = HibernateUtil.getSession() ; Transaction tx1 = session1.beginTransaction() ; User user1 = (User) session.get(User.class, 1) ; user1.setName("李四2") ; session1.update(user1) ; tx1.commit() ; session.update(user) ; tx.commit(); } catch (Exception e) { e.printStackTrace(); } finally { HibernateUtil.closeSession(); } }@Testpublic void testGet1(){Session session=HibernateUtil.getSession();Transaction tx=session.beginTransaction();User user=(User) session.get(User.class, 1);System.out.println(user.getName());user.setName("李四");session.update(user);tx.commit();HibernateUtil.closeSession();}}
执行testSave方法,控制台打印信息
Hibernate: insert into user (version, name, pwd) values (?, ?, ?)数据库表信息
执行testGet1,控制台打印信息
Hibernate: select user0_.id as id1_0_0_, user0_.version as version2_0_0_, user0_.name as name3_0_0_, user0_.pwd as pwd4_0_0_ from user user0_ where user0_.id=?张三Hibernate: update user set version=?, name=?, pwd=? where id=? and version=?
数据库表信息
由图可以看出id和version都发生了改变。
再来测试testGet,控制台打印信息
Hibernate: select user0_.id as id1_0_0_, user0_.version as version2_0_0_, user0_.name as name3_0_0_,
user0_.pwd as pwd4_0_0_ from user user0_ where user0_.id=?Hibernate: update user set version=?, name=?, pwd=? where id=? and version=?Hibernate: update user set version=?, name=?, pwd=? where id=? and version=?org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction
(or unsaved-value mapping was incorrect) : [com.test.pojo.User#1]at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2541)at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3285)at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3183)at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3525)at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:159)at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:465)at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:351)at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1258)at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)at com.test.test.HibernateTest.testGet(HibernateTest.java:52)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:606)at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)at org.junit.runners.ParentRunner.run(ParentRunner.java:300)at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
数据库表信息如下
由数据库中数据得知是user1数据更新到了数据库中,user的数据没有更新到数据库,报错了,这是因为user和user1都从数据库中查询出了version是1的数据,但是user1先更新了数据,然后提交到数据库中,此时该数据库中该数据的version变为了2,等到user也更新数据时,where条件中的version没有找到version是1的对应的数据,所以就报错了。
总结:
1、悲观锁:安全,并发效率低
2、乐观锁:安全性比悲观锁低,并发效率高
如果数据需要大量修改,适用悲观锁。
如果数据是用来读取的,适用乐观锁。
阅读全文
0 0
- Hibernate的悲观乐观锁
- Hibernate的乐观锁与悲观锁
- Hibernate的乐观锁与悲观锁
- Hibernate的悲观锁和乐观锁
- hibernate的 悲观锁和乐观锁
- Hibernate的乐观锁与悲观锁
- Hibernate的乐观锁与悲观锁
- Hibernate的悲观锁和乐观锁
- Hibernate 的乐观锁与悲观锁
- hibernate的悲观锁和乐观锁
- Hibernate的乐观锁与悲观锁
- Hibernate的乐观锁与悲观锁
- Hibernate的乐观锁与悲观锁
- Hibernate的悲观锁和乐观锁
- Hibernate的悲观锁与乐观锁
- Hibernate的悲观锁和乐观锁
- Hibernate的悲观锁和乐观锁
- Hibernate的悲观锁和乐观锁
- POJ2985 The k-th Largest Group(treap+并查集)
- [Hdu] 4417 Super Mario (主席树模板题)
- java各种进制之间的相互转化
- 2017.08.18【NOIP提高组】模拟赛B组 沙耶的玩偶(doll)
- asp.net c# 异步日志通用类(1)
- Hibernate的悲观锁、乐观锁
- 代码详解の使用CountDownLatch解决面试问题:T1和T2线程执行计算,T3线程计算结果的统计
- CodeForces
- C++基本语法,入门及提高(5)
- C++11 lambda 表达式解析
- hdu6141-多校8&最小树形图&朱刘算法-I am your Father!
- IntelliJ 设置全局maven
- 233A. Perfect Permutation
- 邮件服务