Welcome 微信登录

首页 / 数据库 / MySQL / Hibernate事务隔离机制(乐观锁-悲观锁)

事务隔离机制

1、事务:ACID

2、事务并发时可能出现的问题

a) 第一类丢失更新
时间取款事务A存款事务B
T1开始事务 
T2 开始事务
T3查询账户余额为1000元  
T4 查询账户余额为1000元
T5 汇入100元把余额改成1100元
T6 提交事务
T7取出100元把余额改成900元 
T8撤销事务 
T9余额恢复为1000元(丢失更新) 
 b) dirty read脏读(读了另一个事务没有提交的数据)
时间取款事务A存款事务B
T1开始事务 
T2 开始事务
T3 查询账户余额为1000元
T4 汇入100元把余额改成1100元
T5查询账户余额为1100元(读取脏数据) 
T6 回滚
T7取款1100元 
T8事务提交失败 
 c) non-repeatable-read不可重复读(同一个事务中,读取同一个数据,得到的值不同) 
时间取款事务A转账事务B
T1事务开始 
T2 事务开始
T3查询账户余额为1000元 
T4 汇入100元把余额改成1100元
T5 提交事务
T6查询账户余额为1100元 
T7提交事务 
 d)second lost update problems第二类丢失更新(不可重复读的特殊情况)
时间转账事务A取款事务B
T1 开始事务
T2开始事务 
T3 查询账户余额为1000元
T4查询账户余额为1000元 
T5 取出100元把余额改成900元
T6 提交事务
T7汇入100元 
T8提交事务 
T9把余额改成1100元(丢失更新) 
 e) phantom read 幻读(插入、删除问题导致取得的结果不同)
时间查询学生事务A插入学生事务B
T1开始事务 
T2 开始事务
T3查询学生为10人 
T4 插入一个新学生
T5查询学生为11人 
T6 提交事务
T7提交事务 
  

3、数据库的事务隔离机制

1、read-uncommited2、read-commited3、repeatable-read4、serializable a)  只要数据库支持事务,就不会出现read-uncommited情况 b) read-uncommited会出现dirty-read,phantom read,non-repeatable-read问题c) sead-commited不会出现dirty-read,但仍会出现non-repeatable-read,phantom readd) repeatable-reade) serializable解决一切问题  

4、设定hibernate的事务隔离级别

1、为了考虑并发效率,设置Hibernte.connection.isolate=2(即使用的是read-commited)2、用悲观锁解决repeatable read问题(依赖于数据库的锁)A)相当于select ...for update     悲观锁:实验:(1)建立Account.java类package com.zgy.hibernate.model; import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id; @Entitypublic class Account {private int id;private int balance; //BigDecimal@Id@GeneratedValuepublic int getId() {return id;}public void setId(int id) {this.id = id;}public int getBalance() {return balance;}public void setBalance(int balance) {this.balance = balance;}  }(2)HibernateUtil.java,用于获取SessionFactorypackage com.zgy.hibernate.model; import org.hibernate.SessionFactory;import org.hibernate.boot.registry.StandardServiceRegistryBuilder;import org.hibernate.cfg.Configuration;import org.hibernate.service.ServiceRegistry; public class HibernateUtil {static SessionFactory sessionFactory = buildSessionFactory(); private static SessionFactory buildSessionFactory() {Configuration configure = new Configuration().configure();ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configure.getProperties()).build();return sessionFactory = configure.buildSessionFactory(serviceRegistry);} public static SessionFactory getSessionFactory(){return sessionFactory;}}(3)测试类package com.zgy.hibernate.model;  import org.hibernate.LockMode;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;import org.hibernate.tool.hbm2ddl.SchemaExport;import org.junit.AfterClass;import org.junit.BeforeClass;import org.junit.Test; public class HibernateLockTest {private static SessionFactory sf; @BeforeClasspublic static void beforeClass() {sf = HibernateUtil.getSessionFactory();}@AfterClasspublic static void afterClass() {sf.close();} @Testpublic void testSchemaExport() {new SchemaExport(new Configuration().configure()).create(false, true);} @Testpublic void testSave() {Session session = sf.openSession();session.beginTransaction(); Account a = new Account();a.setBalance(100);session.save(a); session.getTransaction().commit();session.close();} @Testpublic void testOperation1() {Session session = sf.openSession();session.beginTransaction(); Account a = (Account)session.load(Account.class, 1);int balance = a.getBalance();//do some caculations,此时如果别的事务在这个过程中对balance进行操作,将会导致banlance取值被此session覆盖balance = balance - 10;a.setBalance(balance);session.getTransaction().commit();session.close();} @Testpublic void testPessimisticlock() {Session session = sf.openSession();session.beginTransaction(); Account a = (Account)session.load(Account.class, 1,LockMode.UPGRADE);int balance = a.getBalance();//do some caculationsbalance = balance - 10;a.setBalance(balance);session.getTransaction().commit();session.close();}public static void main(String[] args) {beforeClass();}}(4)测试testPessimisticlock()方法,观察产生的SQL语句如下:Hibernate:     select        account0_.id as id1_0_0_,        account0_.balance as balance2_0_0_     from        Account account0_     where        account0_.id=? for update            Hibernate:     update        Account     set        balance=?     where        id=?   乐观锁:实验:(1)修改Account.javapackage com.zgy.hibernate.model; import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.Version; @Entitypublic class Account {private int id;private int balance;private int version;@Versionpublic int getVersion() {return version;}public void setVersion(int version) {this.version = version; }@Id@GeneratedValuepublic int getId() {return id;}public void setId(int id) {this.id = id;}public int getBalance() {return balance;}public void setBalance(int balance) {this.balance = balance;}  }  (2)测试:package com.zgy.hibernate.model;  import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;import org.hibernate.tool.hbm2ddl.SchemaExport;import org.junit.AfterClass;import org.junit.BeforeClass;import org.junit.Test;  public class HibernateLockTest {private static SessionFactory sf; @BeforeClasspublic static void beforeClass() {sf = HibernateUtil.getSessionFactory();}@AfterClasspublic static void afterClass() {sf.close();} @Testpublic void testSchemaExport() {new SchemaExport(new Configuration().configure()).create(false, true);} @Testpublic void testSave() {Session session = sf.openSession();session.beginTransaction(); Account a = new Account();a.setBalance(100);session.save(a); session.getTransaction().commit();session.close();} @Testpublic void testOptimisticLock() {Session session = sf.openSession(); Session session2 = sf.openSession();    session.beginTransaction();Account a1 = (Account) session.load(Account.class, 1);  session2.beginTransaction();Account a2 = (Account) session2.load(Account.class, 1); a1.setBalance(900);a2.setBalance(1100); session.getTransaction().commit();System.out.println(a1.getVersion()); session2.getTransaction().commit();System.out.println(a2.getVersion()); session.close();session2.close();} public static void main(String[] args) {beforeClass();}}(3)观察结果: 程序出错,因为session2中的数据被修改或者删除,所以导致session2无法正常关闭。Hibernate整体理解 http://www.linuxidc.com/Linux/2014-07/104405.htmHibernate的映射机制  http://www.linuxidc.com/Linux/2014-12/110265.htmHibernate 的详细介绍:请点这里
Hibernate 的下载地址:请点这里本文永久更新链接地址