热门标签 | HotTags
当前位置:  开发笔记 > 数据库 > 正文

oracle数据库隔离级别学习

这篇文章主要介绍了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多版本机制灵活的,其一严重影响了程序的并发性,读阻塞了写。其二可能引起死锁。


推荐阅读
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 利用存储过程构建年度日历表的详细指南
    本文将介绍如何使用SQL存储过程创建一个完整的年度日历表。通过实例演示,帮助读者掌握存储过程的应用技巧,并提供详细的代码解析和执行步骤。 ... [详细]
  • SQLite 动态创建多个表的需求在网络上有不少讨论,但很少有详细的解决方案。本文将介绍如何在 Qt 环境中使用 QString 类轻松实现 SQLite 表的动态创建,并提供详细的步骤和示例代码。 ... [详细]
  • MySQL 数据库迁移指南:从本地到远程及磁盘间迁移
    本文详细介绍了如何在不同场景下进行 MySQL 数据库的迁移,包括从一个硬盘迁移到另一个硬盘、从一台计算机迁移到另一台计算机,以及解决迁移过程中可能遇到的问题。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 本文详细介绍了如何使用libpq库与PostgreSQL后端建立连接。通过探讨PQconnectdb()函数的工作原理及其在实际应用中的使用方法,帮助读者理解并掌握建立高效、稳定的数据库连接的关键步骤。 ... [详细]
  • 作为一名程序员,从大学步入职场后,常常感受到一种难以言喻的空虚感。这种感觉或许源于对生活的不满、职业发展的瓶颈,或是日常琐事带来的压力。本文将深入探讨这种复杂的情感,并尝试寻找解决之道。 ... [详细]
  • 并发编程:深入理解设计原理与优化
    本文探讨了并发编程中的关键设计原则,特别是Java内存模型(JMM)的happens-before规则及其对多线程编程的影响。文章详细介绍了DCL双重检查锁定模式的问题及解决方案,并总结了不同处理器和内存模型之间的关系,旨在为程序员提供更深入的理解和最佳实践。 ... [详细]
  • 本文深入探讨了C++对象模型中的一些细节问题,特别是虚拟继承和析构函数的处理。通过具体代码示例和详细分析,揭示了书中某些观点的不足之处,并提供了更合理的解释。 ... [详细]
  • 随着网络安全威胁的不断演变,电子邮件系统成为攻击者频繁利用的目标。本文详细探讨了电子邮件系统中的常见漏洞及其潜在风险,并提供了专业的防护建议。 ... [详细]
  • 微软Exchange服务器遭遇2022年版“千年虫”漏洞
    微软Exchange服务器在新年伊始遭遇了一个类似于‘千年虫’的日期处理漏洞,导致邮件传输受阻。该问题主要影响配置了FIP-FS恶意软件引擎的Exchange 2016和2019版本。 ... [详细]
  • 深入理解Spring:Aware接口、异步编程与计划任务
    本文将带你深入了解Spring框架中的 Aware 接口、异步编程以及计划任务。通过具体示例和详细解释,帮助你掌握这些核心功能的实现原理和应用场景。 ... [详细]
  • TechStride 网站
    TechStride 成立于2014年初,致力于互联网前沿技术、产品创意及创业内容的聚合、搜索、学习与展示。我们旨在为互联网从业者提供更高效的新技术搜索、学习、分享和产品推广平台。 ... [详细]
  • 网易严选Java开发面试:MySQL索引深度解析
    本文详细记录了网易严选Java开发岗位的面试经验,特别针对MySQL索引相关的技术问题进行了深入探讨。通过本文,读者可以了解面试官常问的索引问题及其背后的原理。 ... [详细]
  • 前端开发:从底层到顶端的行业现象解析
    在编程领域,鄙视链现象屡见不鲜,从C语言到Java、.NET等,每个技术栈都有其独特地位。然而,前端开发者尽管常处于鄙视链底端,却在市场需求中备受青睐。本文深入探讨这一现象,并分析前端工程师如何在竞争激烈的市场中脱颖而出。 ... [详细]
author-avatar
吴伟琬63526
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有