hibernate事物隔离机制

hibernate事物隔离机制

事务:要么都完成,要么都不完成



a)  事务:ACID

         i.   Atomic ConsistencyItegrity Durability

         

        四个属性ACID:

        A : 原子性 - 要么都完成,要么都不完成

        B:一致性 - 不改变数据的一致性和约束

        C:独立性 - 2个事务不会交错执行

        D:持久性 - 不会无缘无故回顾


b)  事务并发时可能出现的问题:

第一类丢失更新(Lost Update)

时间

取款事务A

存款事务B

T1

开始事务

 

T2

 

开始事务

T3

查询账户余额为1000元

 

T4

 

查询账户余额为1000元

T5

 

汇入100元把余额改为1100元

T6

 

提交事务

T7

取出100元把余额改为900 元

 

T8

撤销事务

 

T9

余额恢复为1000元(丢失更新)

 

   

    dirtyread脏读(读到了另一个事务在处理中还未提交的数据)

时间

取款事务A

存款事务B

T1

开始事务

 

T2

 

开始事务

T3

 

查询账户余额为1000元

T4

 

汇入100元把余额改为1100元

T5

查询账户余额为1100元(读取脏数据)

 

T6

 

回滚

T7

取款1100

 

T8

提交事务失败

 

 

    non-repeatableread 不可重复读(在同一个事务,对同一个数据前后读的值不同)

时间

取款事务A

存款事务B

T1

开始事务

 

T2

 

开始事务

T3

查询账户余额为1000元

 

T5

 

汇入100元把余额改为1100元

T5

 

提交事务

T6

查询帐户余额为1100元

 

T8

提交事务

 

 

    secondlost update problem 第二类丢失更新(不可重复读的特殊情况)

时间

取款事务A

存款事务B

T1

 

开始事务

T2

开始事务

 

T3

 

查询账户余额为1000元

T4

查询账户余额为1000元

 

T5

 

取出100元把余额改为900元

T6

 

提交事务

T7

汇入100元

 

T8

提交事务

 

T9

把余额改为1100元(丢失更新)

 

 

    phantomread 幻读(在读的过程中,另一个事务插入新的记录影响读的结果)

时间

查询学生事务A

插入新学生事务B

T1

开始事务

 

T2

 

开始事务

T3

查询学生为10人

 

T4

 

插入1个学生

T5

查询学生为11人

 

T6

 

提交事务

T7

提交事务

 

c)  数据库的事务隔离机制

        i.   查看 java.sql.Connection 文档

       ii.   4种隔离机制   

    1:read-uncommitted  

    2:read-committed  

    4:repeatable read  

    8:serializable(数字代表对应值)

为什么取值要使用 1 2 4 8而不是 1 2 3 4

1=0000  2=0010 4=01008=1000(位移计算效率高)

1.     只要数据库支持事务,就不可能出现第一类丢失更新

2.     read-uncommitted(允许读取未提交的数据) 会出现dirty read, phantom-read,

non-repeatableread 问题

3.     read-commited(读取已提交的数据项目中一般都使用这个)不会出现dirty read,因为只有另

一个事务提交才会读出来结果,但仍然会出现 non-repeatable read 和 phantom-read

   使用read-commited机制可用悲观锁乐观锁来解决non-repeatable read phantom-read问题

4.     repeatableread(事务执行中其他事务无法执行修改或插入操作    较安全)

5.     serializable解决一切问题(顺序执行事务不并发,实际中很少用)

d)  设定hibernate的事务隔离级别(使用hibernate.connection.isolation配置取值1、2、4、8)

        i.   hibernate.connection.isolation= 2(如果不设 默认依赖数据库本身的级别

       ii.   用悲观锁解决repeatable read的问题(依赖于数据库的锁)

(详见项目 hibernate_3100_Hibernate_Concurrency_Pessimistic_Lock)

1.     select ... for update

2.      使用另一种load方法--load(xx.class , i , LockMode.Upgrade)

a) LockMode.None无锁的机制,Transaction结束时,切换到此模式

b) LockMode.read在査询的时候hibernate会自动获取锁

c) LockMode.write insert  updatehibernate 会自动获取锁

d) 以上3种锁的模式,是hibernate内部使用的(不需要设)

e) LockMode.UPGRADE_NOWAIT是 ORACLE 支持的锁的方式

e)  Hibernate(JPA)乐观锁定(ReadCommitted)

(详见项目hibernate_3200_Hibernate_Concurrency_Optimistic_Lock)

实体类中增加version属性(数据库也会对应生成该字段,初始值为0),并在其get方法前加

@Version注解,则在操作过程中没更新一次该行数据则version值加1,即可在事务提交前判断该数据是否被其他事务修改过.

            @Version

时间

转账事务A

取款事务B

T1

 

开始事务

T2

开始事务

 

T3

查询学生为10人

查询账户余额为1000 version=0

T4

查询账户余额为1000 version=0

 

T5

 

取出100 把余额改为900 version=1

T6

 

提交事务

T7

汇入100元

 

T8

提交事务 ? version>0

throw Exception

 

T9

把余额改为1100元(丢失更新)

 



 悲观锁(使用数据库的锁):


package com.bjsxt.hibernate;


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;
}


}


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 caculation
balance = balance - 10;
a.setBalance(balance);
session.getTransaction().commit();
session.close();
}


乐观锁(自己设置一个版本字段,每次更新检测一下):

package com.bjsxt.hibernate;


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;
}


}


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();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值