Hibernate事务隔离机制(乐观锁-悲观锁)
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-uncommited
2、read-commited
3、repeatable-read
4、serializable
a) 只要数据库支持事务,就不会出现read-uncommited情况
b) read-uncommited会出现dirty-read,phantom read,non-repeatable-read问题
c) sead-commited不会出现dirty-read,但仍会出现non-repeatable-read,phantom read
d) repeatable-read
e) 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;
@Entity
public class Account {
private int id;
private int balance; //BigDecimal
@Id
@GeneratedValue
public 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,用于获取SessionFactory
package 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;
@BeforeClass
public static void beforeClass() {
sf = HibernateUtil.getSessionFactory();
}
@AfterClass
public static void afterClass() {
sf.close();
}
@Test
public void testSchemaExport() {
new SchemaExport(new Configuration().configure()).create(false, true);
}
@Test
public void testSave() {
Session session = sf.openSession();
session.beginTransaction();
Account a = new Account();
a.setBalance(100);
session.save(a);
session.getTransaction().commit();
session.close();
}
@Test
public 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();
}
@Test
public void testPessimisticlock() {
Session session = sf.openSession();
session.beginTransaction();
Account a = (Account)session.load(Account.class, 1,LockMode.UPGRADE);
int balance = a.getBalance();
//do some caculations
balance = 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.java
package com.zgy.hibernate.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Version;
@Entity
public class Account {
private int id;
private int balance;
private int version;
@Version
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
@Id
@GeneratedValue
public 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;
@BeforeClass
public static void beforeClass() {
sf = HibernateUtil.getSessionFactory();
}
@AfterClass
public static void afterClass() {
sf.close();
}
@Test
public void testSchemaExport() {
new SchemaExport(new Configuration().configure()).create(false, true);
}
@Test
public void testSave() {
Session session = sf.openSession();
session.beginTransaction();
Account a = new Account();
a.setBalance(100);
session.save(a);
session.getTransaction().commit();
session.close();
}
@Test
public 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整体理解
Hibernate的映射机制
Hibernate 的详细介绍:请点这里
Hibernate 的下载地址:请点这里
本文永久更新链接地址:
评论暂时关闭