事务隔离机制

数据库事务在并发的时候可能会出一些问题,针对这些问题,数据库本身有一套自己的事务隔离机制,一般的持久层框架也都有自己的隔离机制,这里主要介绍一下hibernate的事务隔离机制和使用方法。

1.数据库在处理并发的时候可能出现的问题。
1.1第一类更新丢失(只有不支持事务的数据库才会发生这种情况,目前常用的数据库Oracle,DB2,mysql 都是没有这个问题的。
事务隔离机制_第1张图片

1.2脏读 一个事务读了另外一个事务没有提交的数据。
事务隔离机制_第2张图片

1.3不可重复读 一个事务中前后两次读取的数据不一致。
事务隔离机制_第3张图片

1.4幻读/虚读 一个事务insert和delete操作对另一个事务的影响
事务隔离机制_第4张图片

2.数据库对以上问题的处理。不同的数据库支持和采取的隔离机制不同,这里就不分类讨论,做一个简单的整理。为了了解这一点,我们可以参照jdbc的java.sql.Connection 这个接口。

事务隔离机制_第5张图片

第一种事不支持事务的事务的数据库,这里不考虑。其他四种一次对应1,2,4,8.事务的隔离机制的等级依次提高,但是效率依次降低。
如何查询和修改当前数据库的隔离机制(以MySQL为例,Oracle复杂些)
mysql:
查询:select @@tx_isolation;
设置:set global transaction isolation level repeatable read;

Oracle明确支持ANSI/ISO SQL92中定义的serializable和read committed两种事务隔离级别。mysql 支持前面提到的四种隔离机制。Oracle的默认隔离机制是read committed,mysql 默认的隔离级别是repeatable read.考虑到并发效率和容错,一般将隔离级别设置为read committed,然后再通过其他手段来处理不可重复读问题(虚读)情况很少,一般不用考虑。

3.hibernate中对事务隔离机制的控制(乐观锁,悲观锁)。
在hibernate中对事务的隔离机制的设置在hibernate.cfg.xml文件中增加
hibernate.connection.isolation 的配置,取值为前面提到的1,2,4,8.
前文提到我们一般数据库的隔离机制设置为2(read committed).那么现在hibernate需要解决的问题就是不可重复读的问题。在处理这一问题上hibernate采用的是乐观锁(optimistic_lock)和悲观锁(pessimistic_lock)。
悲观锁:当事务1查询A记录的时候,事务1没有提交前,其他事务不可对A记录进行任何操作(包括查询)。相当于不管三七二十一,对A记录进行上锁,上锁的语句也即是我们说熟悉的select * from table_1 for update. 如何运用悲观锁(pessimistic_lock),很简单。在load一个对象的时候,增加一个参数LockMode.UPGRADE就可以了。

@Test
    public void testPessimisticLock() {
        Session session = sf.openSession();
        session.beginTransaction();

        Account a = (Account)session.load(Account.class, 1, LockMode.UPGRADE);
        int balance = a.getBalance();
        //一些复杂的处理,
        balance = balance - 10;
        a.setBalance(balance);
        session.getTransaction().commit();
        session.close();
    }

乐观锁:相对于悲观锁从代码中解决,乐观锁是从表结构一侧处理的。他在entity对应的table中增加一个vesion的integer的字段。version字段有一个特点就是,读取该条记录的时候不会跟新version,跟新该条数据version的数据就会加1.下面以Account为例,当事务1读取了记录A,得到version的值是100,当事务1提交的时候,会检查数据库侧该条记录的version字段是否为100,如果是100,则表明其他事务没有对该条记录进行了修改,提交成功,否则提交失败。示用乐观锁更新数据在代码上没有任何区别,关键的区别是在entity中增加了version字段。

package com.bjsxt.hibernate;

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


}

到此为止,简单的介绍了数据库的隔离机制和hibernate的乐观锁和悲观锁。数据库事务是非常复杂的,目前的理解还很肤浅,以后还要更加深入的学习。

你可能感兴趣的:(hibernate,DB)