oracle 数据库隔离级别学习

oracle 事务隔离级别

事务不同引发的状况:
脏读(Dirty reads)
一个事务读取另一个事务尚未提交的修改时,产生脏读
很多数据库允许脏读以避免排它锁的竞争。
不可重复读(Nonrepeatable reads)
同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。
幻读(Phantom reads)
同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻像读。

数据库操作的隔离级别

未提交读(read uncommitted)
提交读(read committed)
重复读(repeatable read)
序列化(serializable)
oracle默认隔离级别read committed (statement level serialization)
每一个语句,在语句开始时,会获取一个此刻的数据快照。
一个事务有多条语句,如果语句之间存在其它完成的事务,这可能引起不可持续读和幻读。

新建一个测试表books:

name,code,price三个字段

添加两条测试数据

使用pl/sql和java程序模拟并发
不允许脏读测试:
程序段首先查询code是qqq的书的价格

代码如下:

//获取连接 省略 
pstat = conn.prepareStatement("select price from books where code='qqq'"); 
rs = pstat.executeQuery(); 
while(rs.next()){ 
  System.out.println("price:"+rs.getDouble(1)); 

close();

输出结果:price:15.0
然后pl/sql执行更新

代码如下:

update books set price=18 where code='qqq';

!pl/sql设置成手动更新,不自动更新
在执行上面java查询代码
输出仍是price:15.0,说明读不到pl/sql中未提交的执行结果,即不允许脏读
pl/sql 执行
commit;

在执行java查询:
输出结果:price:18.0

会有不可重复读何幻读的现象发生就不用测试了吧,
这两种现象都是针对提交后事物的读引起的,read commited隔离级别是允许对提交后
的事物进行读的。

隔离级别:重复读(repeatable read)
这个不允许脏读,不可重复读,但是会有幻读现象。
这个oracle不支持,不好测试。
理解的话就是如果一条查询语句查询的内容有其它事物正在更新的时候,这
查询处于等待状态,直到先前事物提交更新后,才会执行本条查询。也就是
查询的时候也会有锁,需要等待并发的事物释放锁。然后自己获取到锁,执行
自己事物。这样查询也加锁,并发性更低
select ... for update 就是这样可以避免不可重复读的发生

隔离级别:serializable
这个就更严格了,事物执行是一个一个的。一个事务中的语句共享同一个数据快照(在事务开始时存在的数据)。
是事物级别的,脏读,不可重复读,幻读根本就没有机会发生。
前面像read committed都是语句级别的,以语句为单元。
比如
read committed一个事物A有a(select),b(select),c(update)三条语句

当A事物执行a,b的时候,若有B事物执行更新操作,是有可能的
因为a,b是不加锁的

例子:

代码如下:

//获取连接和关闭连接代码 省略 
//不自动提交 
conn.setAutoCommit(false); 
/**
 * a 查询
 */ 
pstat = conn.prepareStatement("select price from books where code='qqq'"); 
rs = pstat.executeQuery(); 
while(rs.next()){ 
    //输出 price:25.0 
    System.out.println("price:"+rs.getDouble(1)); 

close();

/**
 * 暂停一会,用pl/sql执行B事务
 * update books set price=15 where code='qqq';
 * commit;
 */ 
Thread.sleep(10000);

/**
 * 如果这里再执行a查询的话,和第一次查询结果就不一样,因为中间有B事务的提交更新
 * 修改,这也是不可重复读
 */

//b 更新 
pstat = conn.prepareStatement("update books set price=price+10 where code='qqq'"); 
pstat.executeUpdate(); 
close(); 
//c 查询 
pstat = conn.prepareStatement("select price from books where code='qqq'"); 
rs = pstat.executeQuery(); 
while(rs.next()){ 
    //输出 还是price:25.0 ,因为B事务的干预 
    System.out.println("price:"+rs.getDouble(1)); 

close(); 
//提交事务 
conn.commit(); 
if(conn != null){ 
    conn.close(); 
}

上面执行的顺序,事务B是在A的执行过程中执行的。

以上通过实例介绍了oracle数据库隔离级别的相关内容,希望对大家有所帮助。

下面是一些补充:

数据库中的事务基本作用是将数据库从一致状态转换到另一种一致状态,那么事务隔离级别就是定义了一个事务对于另外一个事务做出的修改有多“敏感”。也就是不同的隔离级别定义了事务相互影响的程度,下面分别介绍一下几种不同的隔离级别。

1. READ UNCOMMITTED

其实,oracle不支持这种隔离级别。这种隔离级别允许脏读(也就是可以读取到用户未提交的数据),支持这种隔离级别的数据库主要是为了支持非阻塞读,但是oracle默认支持非阻塞读,所以oracle里面不支持这种隔离级别。下面举一个例子:

如上图所示,假设某一家银行要统计所有账号总共有多少金额。事务A负责统计,事务A从第一行开始读取。假设读取到100行的时候,事务B从账号123转了400元到账户987(事务B还未提交),支持脏读的数据库当事务A读取到342023行的时候,就会得到500元,从而多加了400元。

2. READ COMMITTED

这种隔离级别指的是,事务只能读取已经提交的数据,(但是支持可重复读与幻想读)是oracle数据库默认的隔离模式。其实这种隔离级别在别的数据库里面可能还是会“退化”得像脏读一样。就看前面那个例子,假设在事务A读取到342023行前,事务B提前锁定了这一行,并将金额由100改成了500。那么事务A读取到这一行的时候,发现已经被其他事务锁定了,于是进行等待,直到事务B提交。但是当事务B提交之后,事务A还是读取到了500这一个错误信息,这样就和脏读一样的了,而且还让用户等待这个错误的答案。

3. REPEATABLE READ
这种隔离级别不支持脏读,不支持可重复读,支持幻想读。主要是为了得到一致性的答案与防止丢失更新。

a. 得到一致性答案
在oracle里面这个通过多版本机制得到了实现,但是在其他的数据库需要通过加锁机制进行控制,就以上一个例子为例,怎样才能统计出正确的总金额呢,事务A在读取每一行的时候,给每一行加上共享读锁,这样当事务B执行从账号123转400元到账户987的时候。先是操作第一行将账户123的金额由500修改成100,但是第一行已经被事务A锁定,于是等待,这样事务A能够读取到正确的数据。但是如果事务B执行的操作是从账户987转50元到账户123的时候,事务B先操作第342023行,发现没有被锁定,于是锁定将金额由100修改成50,然后操作第一行,发现锁定了于是等待。而事务A读取到342023行的时候,发现这一行已经被事务B锁定于是等待,这样就陷入了死锁。

b. 丢失更新
在采用共享读锁的数据库中,这种隔离级别可以防止丢失更新,比如事务1先读取了第A行然后修改了这一行的C列(其他列也修改了只是值还和以前一样,因为程序员都是整行的更新)。这个时候事务2想也想修改A行的时候会被阻塞,防止事务1的更新被覆盖。

4. SEAIALIZABLE

不允许脏读,重复读与幻想读,最高的隔离级别。这种隔离级别标明事务A在操作数据库的时候好像就只有事务A在操作,没有其他事务在操作数据库一样。
Oracle 中是这样实现 SERIALIZABLE 事务的:原本通常在语句级得到的读一致性现在可以扩展到事务级。也就是在事务执行的那一刻,将这个事务将要操作的数据拍了一张照片。

从上面的例子我们可以看出,其他数据库采用共享读锁来解决统计总金额问题是没有oracle多版本机制灵活的,其一严重影响了程序的并发性,读阻塞了写。其二可能引起死锁。

(0)

相关推荐

  • mysql+Spring数据库隔离级别与性能分析

    这里以mysql为例,先明确以下几个问题: 一.一般项目如果不自己配置事务的话,一般默认的是autocommit,即执行完一个操作后自动commit,提交事务. (注:事务是绑定在数据库操作上的,也就是当程序执行(statement.excute等操作)转而到数据库层面上的时候,事务才开始发生)当然spring可以将几个数据库操作动作绑在一个事务中,这样就需要介绍下spring事务配置方法,下面介绍的是常用方法,其他方法网上有很多.spring提供了很多事务配置的策略,很方便,简要介绍一下: 复

  • 深入解析MySQL的事务隔离及其对性能产生的影响

    SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的.低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销. Read Uncommitted(读取未提交内容)        在该隔离级别,所有事务都可以看到其他未提交事务的执行结果.本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少.读取未提交的数据,也被称之为脏读(Dirty Read). Read Committed(读取提交内容)        这是大多数数据库系统的默认隔离

  • MySQL数据库事务隔离级别介绍(Transaction Isolation Level)

    数据库隔离级别有四种,应用<高性能mysql>一书中的说明: 然后说说修改事务隔离级别的方法: 1.全局修改,修改mysql.ini配置文件,在最后加上 复制代码 代码如下: #可选参数有:READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE. [mysqld] transaction-isolation = REPEATABLE-READ 这里全局默认是REPEATABLE-READ,其实MySQL本来默认也是这个级别

  • ORACLE数据库事务隔离级别介绍

    两个并发事务同时访问数据库表相同的行时,可能存在以下三个问题: 1.幻想读:事务T1读取一条指定where条件的语句,返回结果集.此时事务T2插入一行新记录,恰好满足T1的where条件.然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这条新纪录就是幻想. 2.不可重复读取:事务T1读取一行记录,紧接着事务T2修改了T1刚刚读取的记录,然后T1再次查询,发现与第一次读取的记录不同,这称为不可重复读. 3.脏读:事务T1更新了一行记录,还未提交所做的修改,这个T2读取了更新后的数据

  • 浅谈InnoDB隔离模式的使用对MySQL性能造成的影响

    在这篇文章里我将讨论一个相关的主题 – InnoDB 事务隔离模式,还有它们与MVCC(多版本并发控制)的关系,以及它们是如何影响MySQL性能的. MySQL手册提供了一个关于MySQL支持的事务隔离模式的恰当描述 – 在这里我并不会再重复,而是聚焦到对性能的影响上. SERIALIZABLE – 这是最强的隔离模式,本质上打败了在锁管理(设置锁是很昂贵的)的条件下,多版本控制对所有选择进行锁定造成大量的开销,还有你得到的并发.这个模式仅在MySQL应用中非常特殊的情况下使用. REPEATA

  • 深入分析MSSQL数据库中事务隔离级别和锁机制

    锁机制 NOLOCK和READPAST的区别. 1.       开启一个事务执行插入数据的操作. BEGIN TRAN t INSERT INTO Customer SELECT 'a','a' 2.       执行一条查询语句. SELECT * FROM Customer WITH (NOLOCK) 结果中显示"a"和"a".当1中事务回滚后,那么a将成为脏数据.(注:1中的事务未提交) .NOLOCK表明没有对数据表添加共享锁以阻止其它事务对数据表数据的修

  • MSSQL与Oracle数据库事务隔离级别与锁机制对比

    一,事务的4个基本特征 Atomic(原子性): 事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要 么全部成功,要么全部失败. Consistency(一致性): 只有合法的数据可以被写入数据库,否则事务应该将其回滚到最初 状态. Isolation(隔离性): 事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正 确性和完整性.同时,并行事务的修改必须与其他并行事务的修改 相互独立. Durability(持久性): 事务结束后,事务处理的结果必须能够得到固化. 以上属于废话

  • MySQL中Innodb的事务隔离级别和锁的关系的讲解教程

    前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力.所以对于加锁的处理,可以说就是数据库对于事务处理的精髓所在.这里通过分析MySQL中InnoDB引擎的加锁机制,来抛砖引玉,让读者更好的理解,在事务处理中数据库到底做了什么. 一次封锁or两段锁? 因为有大量的并发访问,为了预防死锁,一般应用中推荐使用一次封锁法,就是在方法的开始阶段,已经预先知道会

  • 深入理解Mysql的四种隔离级别

    一.首先什么是事务? 事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消.也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做. 事务的结束有两种,当事务中的所以步骤全部成功执行时,事务提交.如果其中一个步骤失败,将发生回滚操作,撤消撤消之前到事务开始时的所以操作. 二.事务的 ACID 事务具有四个特征:原子性( Atomicity ).一致性( Consistency ).隔离性( Isolation )和持续性( Dura

  • 浅析MYSQL REPEATABLE-READ隔离级别

    REPEATABLE-READ 即可重复读,set autocommit= 0或者START TRANSACTION状态下select表的内容不会改变.这种隔离级别可能导致读到的东西是已经修改过的. 比如: 回话一中读取一个字段一行a=1 在回话二里这个字段该行修改a=0,并且提交 回话一中再update这个字段a=0,会发现受影响行数是0,这样就可以根据受影响行数是0还是1判断此次修改是否成功! 这在某些程序里会很有用! 会话1: mysql> set autocommit=0; Query

随机推荐