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-readphantom 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(falsetrue);

}

 

@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(falsetrue);

}

 

@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 的下载地址:请点这里

本文永久更新链接地址:

相关内容