Oracle事务是怎么练成的

news2024/11/25 12:43:33

什么是事务

事务是数据库管理系统执行过程的一个逻辑单位,由一系列有限的数据库操作序列构成,事务必须满足‌ACID属性。ACID理论是数据库中最重要的概念之一,分别代表原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。

  • 原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生;
  • 一致性是指事务将数据库从一个一致的状态转移到另一个一致的状态,这意味着事务执行的结果必须符合所有预定义的规则和约束;
  • 隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离;
  • 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

最经典的事务就是银行转账的例子:小明从自己的账户往小红账户汇款1000元,对应数据库的操作如下。

update account set balance = balance - 1000 where name = 'xiaoming';
update account set balance = balance + 1000 where name = 'xiaohong';

如果只是第一条语句正常执行,小明白白损失1000元,肯定要找银行的麻烦;如果第一条失败第二条正常执行,银行白白损失1000元,长此以往估计要破产。所以看似简单的两条语句,执行起来却需要遵循ACID特性来保证数据的一致性。

关系型数据库普遍支持事务,Oracle是一个强一致性的关系型数据库,设计上严格遵守了事务ACID特性。那么Oracle数据库有哪些设计来实现事务的ACID呢?

事务隔离性与隔离级别

事务是由多个原子操作组合而成,因此会出现中间状态。比如前面转账的例子,当执行完第一条语句后,因为某种原因没有继续往下执行,而是暂停了程序(注意,事务并没有结束)。第二个会话去查询时会发现,账户余额仍然是1500,并没有发生改变。

## session 1
## 假设更新之前账户余额为1500
update account set balance = balance - 1000 where name = 'xiaoming';

## session 2
## 第二个会话查询结果仍然是1500
select balance from account where name = 'xiaoming';

当数据库上有多个事务并发执行的时候,不同事务之间会产生相互影响,上面的例子中,两个会话操作的是同一个账户的数据,当会话1事务没结束之前,会话2返回了会话1修改之前的数据。那会话2查询到的数据是正确的吗?这个其实是事务隔离性的一种体现,在数据库概念中有个专门的名词叫“隔离级别”。

根据各种可能的场景,SQL标准的隔离级别被定义为四种类型:读未提交(Read Uncommitted)、读提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。

隔离级别定义优点缺点
读未提交一个事务还没提交时,它所做的变更就能被其他事务看到事务之间没有任何隔离,并发度好如果未提交的数据时候回滚,读取将是无效的,产生“脏读”
读已提交一个事务提交之后,它所做的变更才能被其他事务看到常见的隔离级别,比较符合业务逻辑需求同一个事务多次查询可能得到不同的结果,产生“幻读”
可重复读一个事务执行过程中看到的数据,总是和这个事务在启动时看到的数据一致常见的隔离级别,避免产生“幻读”,有一定的应用场景隔离代价更高,对应用并发执行有一定的影响
串行化在上一个事务未提交之前,任何其他的事务都不能访问这个数据事务之间完全隔离应用不能并发访问,对性能有严重的影响

为了便于大家的理解,我把四种类型的隔离级别的定义及优缺点用表格的方式呈现出来,相信大家已经看出来了,四种隔离级别是层层递进的,越往后隔离程度越高,对并发访问的影响也越大。简单来说,隔离程度越高效率就越低,因此我们需要在二者之间寻找一个平衡点。

不同的数据库有自己默认的隔离级别,在Oracle中默认是“读已提交”,也就是说在一个事务没有提交之前,其他会话看不到数据变化的中间状态。所以上面银行转账的例子,如果继续执行下去,我们会得到以下的结果。

时间点会话1会话2
09:00:00xiaoming账户转出1000元,余额500元
09:00:01查询xiaoming账户余额仍为1500元
09:00:02提交事务
09:00:03查询xiaoming账户余额为500元

会话2两次查询结果不一样,就是我们所说的“幻读”,这可能会对我们的业务处理造成一定的困扰。比如有两张表,分别是账户余额和交易明细,月底数据核对的时候如果有用户触发了新的交易,可能会让你两次查询得到不同的结果,影响你的核对工作。

为了避免“幻读”现象,也有一些数据库,比如MySQL数据库,默认隔离级别是"可重复读“,上面的例子在MySQL默认隔离级别下的表现是这样的。

时间点会话1会话2
09:00:00xiaoming账户转出1000元,余额500元开启事务
09:00:01查询xiaoming账户余额仍为1500元
09:00:02提交事务
09:00:03查询xiaoming账户余额仍为1500元
09:00:04提交事务
09:00:05查询xiaoming账户余额为500元

这次会话2的事务提交之前,查询的结果始终没有发生变化,避免了“幻读”的发生。因此在MySQL和Oracle之间的迁移,需要注意数据库默认的隔离级别,相同的应用程序可能跑出来不同的结果。

此外也需要提醒大家的是,为了提升一个隔离级别,衍生出来一系列的加锁操作,增加了实现的难度,对应用的并发也有一定的影响。

Oracle隔离性的实现

多版本并发控制(Multi-Version Concurrency Control, MVCC)是一种用于提高数据库并发性能的技术,在早先的Oracle时代却很少有人提及。事实上,早在Oracle 8i的时代就支持MVCC技术,其实现方式是在数据库中引入Undo表空间,通过Undo来构造一致性读,以此来实现并发事务之间的数据隔离。
在这里插入图片描述

在《Oracle日志系统:一条SQL更新语句是如何执行的》这篇文章中,介绍数据更新时提到了“前镜像”,这个前镜像的数据就保存在Undo表空间。事务开始时会在Undo表空间中分配一个Undo段,当数据发生改变时,原始值会被拷贝到Undo段。当有会话读取到未提交的数据时,会通过链接指向Undo段,读取Undo段中的“前镜像”值。早期的数据库中,Oracle有一项非常傲人的特性 – 读永远都不会被阻塞,就是通过Undo来实现的。

但是Undo表空间也是有限的,Undo段中的数据不可能永久保留。那么什么时候其中的数据才可以被覆盖呢?答案是最少要保留到事务的正常结束。但如果仅仅保留到事务结束是否够用呢,我们看看下面的场景。

时间点会话1会话2
09:00:00开启事务,更新表A数据
09:01:00查询表A数据
09:05:00提交事务
09:30:00查询结束

会话1在09:00开始事务,09:05结束事务。同时会话2在09:01开始一个新的查询,但是这个查询执行了29分钟,直到09:30才结束,如果在09:30之前和表A相关的Undo数据被清理,会话2就会报出ORA-01555的错误。这是在早期Oracle数据库中非常经典的错误,触发错误的原因就是会话需要读取Undo数据但已经被清理。

由于所保存数据的特殊性,Undo表空间的管理上和其他表空的区别很大,限于篇幅的原因,我们在后面有专门的章节详细讲解。

事务的开始和结束

事务由事务开始与事务结束之间执行的全部数据库操作构成,这些操作要么全部成功,要么全部失败,必须以一个整体面向数据库,这就是事务的原子性。

不同事务的开始和结束标志有所差别,Oracle数据库事务的开始通常有两种方式:

  1. 以DML语句开始,表示一个事务的开始,这种也称为隐式事务开始;
  2. 以关键字BEGIN表示事务的开始,这种也称为显示事务开始。

事务的结束有三种方式:

  1. 以关键字COMMIT或ROLLBACK表示事务的结束,这种称为显示事务结束。如果事务以COMMIT结束,则意味着数据更新被确认,更新后的数据将最终会被写入到磁盘中;如果事务以ROLLBACK结束,则意味着放弃本次更新操作,所有在这个事务中的操作都会回滚到更新之前的状态;
  2. 会话正常退出,比如执行某个DML操作后执行exit退出会话,这个操作包含隐式的COMMIT,之前的操作会被保存更新;
  3. 会话异常退出,比如会话进程被kill,这个则意味着隐式的ROLLBACK,所有的操作会回滚到更新之前的状态。

总结

这篇文章中,我们给大家介绍了Oracle数据库事务隔离的原理和实现,通过引入Undo段构造“前镜像”,Oracle实现了在Read Committed级别下的事务隔离。

由于Undo数据的特殊性,其管理上和其他表空间的差别也很大,大家遇到过哪些Undo相关的错误,又是如何解决的呢?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2035896.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人工智能GPU算力评估分析

GPU算力评估 一、 关于训练GPU的带宽 大模型训练算力需求:总算力(Tlops)6倍模型参数量训练数据token量,精准高效满足大规模训练需求。 需要把那么计算量和通信量的比例是多少? 3:指的是一次正向两次反向,反向是梯度…

程序员职场升级攻略:学AI技能,稳步迈向月薪破万之路

在人工智能高速发展的今天,AI技术已经成为职场人士提升收入的有力武器。许多人通过学习AI技能,成功跻身高收入行业,实现了月薪破万的目标。本文将揭秘高收入行业与城市,并提供一条清晰的学习路线,助你成为AI领域的一员…

ubuntu:更新阿里云apt源

前言 我用vmware也搭建了ubuntu服务器,并同样发现apt几乎完全用不了(系统默认用的是清华源,可能较老了) 更新阿里云apt源 1、去阿里云官网找系统对应的apt源配置 阿里云镜像:阿里巴巴开源镜像站-OPSX镜像站-阿里云开发…

Unity教程(九)角色攻击的改进

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程(零)Unity和VS的使用相关内容 Unity教程(一)开始学习状态机 Unity教程(二)角色移动的实现 Unity教程(三)角色跳跃的实现 Unity教程&…

WindowsAPI 查阅笔记:进程间管道通信

进程间有名管道的通信: 1.1 重叠I/O(Overlapped I/O) 重叠I/O(Overlapped I/O)是Windows编程中的一种异步 I / O 处理方式,它允许程序在发出I/O请求后继续执行其他任务,而不必等待I/O操作完成…

萌啦定价工具,萌啦数据ozon定价工具

在电商行业日益竞争激烈的今天,精准定价成为了商家们获取市场竞争优势的关键一环。尤其是对于在Ozon平台上耕耘的卖家而言,无论是本土卖家还是跨境商家,如何快速、准确地制定出既符合市场需求又能保障利润的价格策略,成为了亟待解…

高防服务器的机制和原理

高防服务器是一种具备强大防御能力的服务器,旨在保护网站免受各种网络攻击,如DDoS(分布式拒绝服务)攻击、CC(ChallengeCollapsar)攻击等。今天小编将从流量过滤与清洗、负载均衡与反向代理、实时监控与报警…

圈内水刊“三巨头”之首实至名归?发文量飙升至9000+,硕博小白照样发1区TOP!

【SciencePub学术】昨天,小编给大家介绍了环境水刊“三巨头”之一的《Journal of Hazardous Materials》,本期,给大家带来的是位于环境水刊“三巨头”之首的《Science of the Total Environment》,属于JCR1区中科院1区TOP&#xf…

冷数据归档(历史库),成本与性能如何兼得?| OceanBase应用实践

随着数据量的迅猛增长,企业和组织在数据库管理方面遭遇的挑战愈发凸显。数据库性能逐渐下滑、存储成本节节攀升,以及数据运维复杂性的增加,这些挑战使得DBA和开发者在数据管理上面临更大的压力。 为了应对这些挑战,对数据生命周期…

vulnstack-5

环境搭建 靶场虚拟机共用两个,一个外网一个内网,用来练习红队相关内容和方向,主要包括常规信息收集、Web攻防、代码审计、漏洞利用、内网渗透以及域渗透等相关内容学习。 虚拟机密码 win7 sun\heart 123.com sun\Administrator dc123.com # …

华为软件测试笔试真题,赶快收藏

软件测试工程师笔试题目 一.填空 1、 系统测试使用( C )技术, 主要测试被测应用的高级互操作性需求, 而无需考虑被测试应用的内部结构。 A、 单元测试 B、 集成测试 C、 黑盒测试 D、白盒测试 2、单元测试主要的测试技术不包括(…

【nvidia-smi】Failed to initialize NVML: Driver/library version mismatch

服务器更新后,输入nvidia-smi出现如下报错: 解决方法参考: 已解决【nvidia-smi】Failed to initialize NVML: Driver/library version mismatch解决方法-腾讯云开发者社区-腾讯云 (tencent.com) 输入命令查看nvidia驱动的版本号&#xff1a…

Linux软件包yum

目录 Linux软件包管理器 yum关于rzsz注意事项查看软件包如何安装软件卸载命令 Linux开发工具Linux编辑器-vim使用1. vim的基本概念2. vim的基本操作3. vim正常模式命令集4. vim末行模式命令集5. vim操作总结 小彩蛋 Linux软件包管理器 yum 软件包 在Linux下安装软件&#xff…

java基础学习笔记2(8.9)

String equals比较堆里值 字符串比较用str1.equals(str2); 比较栈里的值 JDK7以后字符串常量池进入了堆里面。 在Java中,StringBuffer 和 StringBuilder 是用于创建可变字符串的类。它们提供了比 String 更高效的字符串操作,尤其是在需要…

ICM-20948芯片详解(13)

接前一篇文章:ICM-20948芯片详解(12) 六、寄存器详解 2. USER BANK 0寄存器详述 (60)FIFO_COUNTH 高5位,计数表示FIFO中写入的字节数。 (61)FIFO_COUNTL 低8位,计数表…

IMAX ENHANCED认证的护眼三色激光投影仪,选极米 RS 10 Pro把专业IMAX影院带回家

对于追求大屏体验的用户来说,智能投影仪有着电视机无法比拟的优势。因此,智能投影仪如今也逐步替代传统电视机,成为了许多家庭的必备家电之一。对于当代年轻人而言,无论是追剧、看电影还是打游戏,大屏幕都始终比传统电…

西部数据拒绝2.62亿美元巨额赔偿:硬盘专利侵权案将上诉

西部数据(Western Digital,简称WD)被加州的一个陪审团裁定需支付2.62亿美元的赔偿金,原因是该公司侵犯了德国科学家Dieter Suess拥有的硬盘驱动器(HDD)记录技术专利。Suess是维也纳大学功能性材料物理学教授…

linux系统编程:进程(2)

1.在fork函数前打开函数和fork之后打开文件区别 1.fork之前open 子进程会继承父进程已打开的文件的相关信息所以,此时父子进程 会影响统一个offset值 2.fork之后open 父子进程各自有各自的打开文件的信息:相互之间不会有影响。 2.进程创建好之后: 1.任务--- …

Java流程控制01:用户交互Scanner

本节教学视频链接:https://www.bilibili.com/video/BV12J41137hu?p33&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5https://www.bilibili.com/video/BV12J41137hu?p33&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 Scanner 类用于扫描输入文本从字符串中提…

具备长短距离注意力模块的Lite Transformer

Transformer在自然语言处理(例如,机器翻译、问答)中已经变得无处不在;然而,它需要大量的计算才能实现高性能,这使得它不适合受硬件资源和电池严格限制的移动应用程序。在本文中,提出了一个高效的移动NLP架构,Lite Tran…