首页 > 数据库 > 其他综合 >

Hibernate事务隔离机制(乐观锁-悲观锁)

2015-01-18

事务隔离机制 1、事务:ACID 2、事务并发时可能出现的问题 a) 第一类丢失更新 时间 取款事务A 存款事务B T1 开始事务 T2 开始事务 T3 查询账户余额为1000元 T4

事务隔离机制

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无法正常关闭。

相关文章
最新文章
热点推荐