Oracle事务是怎么练成的
什么是事务
事务是数据库管理系统执行过程的一个逻辑单位,由一系列有限的数据库操作序列构成,事务必须满足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:00 | xiaoming账户转出1000元,余额500元 | |
| 09:00:01 | 查询xiaoming账户余额仍为1500元 | |
| 09:00:02 | 提交事务 | |
| 09:00:03 | 查询xiaoming账户余额为500元 |
会话2两次查询结果不一样,就是我们所说的“幻读”,这可能会对我们的业务处理造成一定的困扰。比如有两张表,分别是账户余额和交易明细,月底数据核对的时候如果有用户触发了新的交易,可能会让你两次查询得到不同的结果,影响你的核对工作。
为了避免“幻读”现象,也有一些数据库,比如MySQL数据库,默认隔离级别是"可重复读“,上面的例子在MySQL默认隔离级别下的表现是这样的。
| 时间点 | 会话1 | 会话2 |
|---|---|---|
| 09:00:00 | xiaoming账户转出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数据库事务的开始通常有两种方式:
- 以DML语句开始,表示一个事务的开始,这种也称为隐式事务开始;
- 以关键字BEGIN表示事务的开始,这种也称为显示事务开始。
事务的结束有三种方式:
- 以关键字COMMIT或ROLLBACK表示事务的结束,这种称为显示事务结束。如果事务以COMMIT结束,则意味着数据更新被确认,更新后的数据将最终会被写入到磁盘中;如果事务以ROLLBACK结束,则意味着放弃本次更新操作,所有在这个事务中的操作都会回滚到更新之前的状态;
- 会话正常退出,比如执行某个DML操作后执行exit退出会话,这个操作包含隐式的COMMIT,之前的操作会被保存更新;
- 会话异常退出,比如会话进程被kill,这个则意味着隐式的ROLLBACK,所有的操作会回滚到更新之前的状态。
总结
这篇文章中,我们给大家介绍了Oracle数据库事务隔离的原理和实现,通过引入Undo段构造“前镜像”,Oracle实现了在Read Committed级别下的事务隔离。
由于Undo数据的特殊性,其管理上和其他表空间的差别也很大,大家遇到过哪些Undo相关的错误,又是如何解决的呢?
相关文章:
Oracle事务是怎么练成的
什么是事务 事务是数据库管理系统执行过程的一个逻辑单位,由一系列有限的数据库操作序列构成,事务必须满足ACID属性。ACID理论是数据库中最重要的概念之一,分别代表原子性(Atomicity)、一致性(Consisten…...
线程与多线程(一)
线程与多线程(一) 一、线程1、概念2、示意图3、虚拟地址转换到物理地址4、与进程相比的优点5、与进程相比的缺点6、与进程的关系(1)线程独有(2)共享(3)示意图 二、POSIX线程库三、创…...
连接其他主机上的redis连接不上`telnet: Unable to connect to remote host: Connection refused`
telnet: Unable to connect to remote host: Connection refused 这个错误通常表示目标主机(192.168.8.29)上的服务(6379端口)没有运行,或者主机的防火墙/网络设置阻止了连接。 你可以尝试以下步骤来解决问题…...
dijkstral算法详解
import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map;public class test39 {// 定义节点类,表示图中的顶点public static class Node {public int value; // 节点的值,即编号public int in; // 进入…...
创意指南丨AR数学沉浸式空间体验
AR学习种类那么多,哪款最吸引你? 星河造梦坊和Unity联手打造的沉浸式空间AR无疑是其中的佼佼者。 这款应用不仅利用AR技术将抽象的数学概念变得生动有趣,还通过互动体验让学习者仿佛置身于一个充满奇幻色彩的数学世界中。 无论是学生还是教…...
linux文件——深度学习文件fd、文件系统调用
前言:从本片开始正式进入linux文件的学习,本片内容主要是文件的fd。 本篇内容博主将要先带友友回忆C语言中的文件操作接口,然后再过渡到操作系统中的系统调用的学习,最后理解操作系统中的文件操作。 ps:本节内容设计一…...
003集——C#数据类型 及大小端序转换——C#学习笔记
如需得到一个类型或一个变量在特定平台上的准确尺寸,可以使用 sizeof 方法。表达式 sizeof(type) 产生以字节为单位存储对象或类型的存储尺寸。下面举例获取任何机器上 int 类型的存储尺寸: using System;namespace DataTypeApplication {class Program{…...
结构化输出及其使用方法
在 LLM 应用程序中构建稳健性和确定性 图片来自作者 欢迎来到雲闪世界。OpenAI最近宣布其最新的gpt-4o-2024–08–06模型支持结构化输出。与大型语言模型 (LLM) 相关的结构化输出并不是什么新鲜事——开发人员要么使用各种快速工程技术,要么使用第三方工具。 在本文…...
yolov8人脸识别案例
GitHub - wangWEI201901/YOLOv8-Detection-Project: 🛣️基于YOLOv8的智慧校园人脸识别和公路汽车检测...
成员变量在Java中的定义与使用
成员变量在Java中的定义与使用 大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在本文中,我们将详细探讨Java中的成员变量,包括其定义、使用以及各种类型的成员变量示例。 成员…...
Python开发工具PyCharm入门指南 - 用户界面主题更改
JetBrains PyCharm是一种Python IDE,其带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具。此外,该IDE提供了一些高级功能,以用于Django框架下的专业Web开发。 界面主题定义了窗口、对话框、按钮和用户界面的所有可视元素的外观…...
TCP网络套接字
一、创建套接字 #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); 参数: domain:指定使用的协议族。常见的取值有AF_INET(IPv4)和AF_INET6(IPv6&a…...
Element学习(axios异步加载数据、案例操作)(5)
1、这次学习的是上次还未完成好的恶element案例,对列表数据的异步加载,并渲染展示。 ——>axios来发送异步请求 (1) (2)在vue当中安装axios (注意在当前的项目目录,并且安装完之后…...
大数据-65 Kafka 高级特性 分区 Broker自动再平衡 ISR 副本 宕机恢复再重平衡 实测
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...
html+css+js网页设计 软通动力网站2个页面(带js)首页轮播图+置顶导航
htmlcssjs网页设计 软通动力网站2个页面(带js)首页轮播图置顶导航 网页作品代码简单,可使用任意HTML编辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及…...
【经验分享】ShardingSphere+Springboot-04:自定义分片算法(COMPLEX/STANDARD)
文章目录 3.4 CLASS_BASED 自定义类分片算法3.4.1 复杂分片自定义算法(strategyCOMPLEX )3.4.2 STANDARD 标准分片自定义算法## 进阶:star: 自定义算法范围查询优化 3.4 CLASS_BASED 自定义类分片算法 3.4.1 复杂分片自定义算法(strategyCOM…...
如何设置RabbitMQ和Redis消息队列系统
设置RabbitMQ和Redis作为消息队列系统时,需要分别进行安装、配置和测试,以确保它们能够正常工作并满足你的应用需求。以下是一个基于这两个系统的设置指南: RabbitMQ的设置 1. 安装Erlang 由于RabbitMQ是用Erlang语言编写的,因…...
白骑士的Matlab教学高级篇 3.3 工具箱与扩展
MATLAB 提供了丰富的工具箱(Toolbox)和扩展功能,这些工具箱涵盖了各个领域的专业计算需求,如信号处理、图像处理、统计与机器学习等。利用工具箱,用户可以快速实现复杂的计算和分析任务。本文将介绍常用的工具箱及其使…...
bug: 配置flyway.locations多个脚本位置不生效
文章目录 业务场景场景一场景二 业务场景 随着项目版本迭代,数据库结构也会变动。如果一个项目引用其他项目的jar包,并且需要执行对应jar包的flyway脚本,就需要配置flyway.locations 场景一 正常情况下,在一个项目中可以在yml文件…...
8月5日SpringBoot学习笔记
今日内容:搭建mybatis ORM 配置数据源 $#的区别 增删改查 搭建mybatis 在原有maven项目基础配置上进行: pom文件添加依赖 <!-- Mybatis --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...
