MySQL事务控制流与ACID特性
作者:Wallace JW 发布时间:2024-01-24 23:03:50
目录
一、ACID 特性
二、事务控制语法
三、事务并发异常
1、脏读
2、不可重复读
3、幻读
四、事务隔离级别
一、ACID 特性
事务处理是一种对必须整批执行的 MySQL 操作的管理机制,在事务过程中,除非整批操作全部正确执行,否则中间的任何一个操作出错,都会回滚 (Rollback)
到最初的安全状态以确保不会对系统数据造成错误的改动。
MySQL 5.5 之后,默认的存储引擎从 MyLSAM 替换成了 InnoDB,这其中的一个重要原因就是因为 InnoDB 支持事务,我们用 SHOW ENGINES
来看一下 MySQL 中对各种存储引擎的描述。
事务最重要的四个特性通常被称为 ACID
特性:A - Atomicity 原子性:
一个事务是一个不可分割的最小单位,事务中的所有操作要么全部成功,要么全部失败,没有中间状态。原子性主要是通过事务日志中的回滚日志(undo log)来实现的,当事务对数据库进行修改时,InnoDB 会根据操作生成相反操作的 undo log,比如说对 insert 操作,会生成 delete 记录,如果事务执行失败或者调用了 rollback,就会根据 undo log 的内容恢复到执行之前的状态。
C - Consistency 一致性:
事务执行之前和执行之后数据都是合法的一致性状态,即使发生了异常,也不会因为异常引而破坏数据库的完整性约束,比如唯一性约束等。
I - Isolation 隔离性:
每个事务是彼此独立的,不会受到其他事务的执行影响,事务在提交之前对其他事务不可见。隔离性通过事务的隔离级别来定义,并用锁机制来保证写操作的隔离性,用 MVCC 来保证读操作的隔离性,将在下文详细介绍。
D - Durability 持久性:
事务提交之后对数据的修改是持久性的,即使数据库宕机也不会丢失,通过事务日志中的重做日志(redo log)来保证。事务修改之前,会先把变更信息预写到 redo log 中,如果数据库宕机,恢复后会读取 redo log 中的记录来恢复数据。
二、事务控制语法
MySQL 事务控制有几个重要节点,分别是事务的开启,提交,回滚和保存点。
开启事务代表事务开始执行,语句为 START TRANSACTION
或者 BEGIN
,提交事务代表将事务中的所有更新都写到磁盘的物理数据库,事务正常执行结束,语句为 COMMIT
,如果发生异常需要回滚,语句为 ROLLBACK
。要注意的是,一旦事务已经提交,就不能回滚了,因此,在代码执行过程中捕获到异常的时候需要直接执行 rollback 而不是 commit。
比如 A 向 B 转账 100 元的事务:
// 正常执行,提交
BEGIN; # 开启事务
UPDATE account_balance SET balance = balance - 100.00 WHERE account_name = 'A';
UPDATE account_balance SET balance = balance + 100.00 WHERE account_name = 'B';
COMMIT; # 提交事务
// 发生异常,回滚
BEGIN; # 开启事务
UPDATE account_balance SET balance = balance - 100.00 WHERE account_name = 'A';
UPDATE account_balance SET balance = balance + 100.00 WHERE account_name = 'B';
ROLLBACK; # 事务回滚
在复杂场景中,有时我们不需要全盘回滚整个操作,而是分批执行,回滚到某个节点就好了,相当于是在一个大事务下嵌套了若干个子事务,在 MySQL 中可以使用保留点 SAVEPOINT
来实现。
BEGIN;
insert into user_tbl (id) values (1) ;
insert into user_tbl (id) values (2) ;
ROLLBACK; # 1,2 都没有写入
BEGIN;
insert into user_tbl (id) values (1) ;
SAVEPOINT s1;
insert into user_tbl (id) values (2) ;
ROLLBACK TO s1; # 回滚到保留点 s1, 因此 1 成功写入,2 被回滚, 最终结果为 1
RELEASE SAVEPOINT s1; # 释放保留点
顺便提一下,事务有隐式事务(自动提交)和显示事务(必须手动提交)两种,MySQL 默认为隐式事务,会进行自动提交,通过 autocommit
参数来控制。
# 查看变量
SHOW VARIABLES LIKE 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
# 开启自动提交(默认)
SET autocommit = 1;
# 关闭自动提交
SET autocommit = 0;
在自动提交状态下,如果没有显示的开启事务,那每一条 DML 语句都是一个事务,系统会自动对每一条 sql 执行 commit 操作。使用 BEGIN 或 START TRANSACTION 开启一个事务之后,自动提交将保持禁用状态,直到使用 COMMIT 或 ROLLBACK 结束事务之后,自动提交模式会恢复到之前的状态。
关于事务还有另一个参数 completion_type,
默认取值为 0 (NO_CHAIN)
# 查看变量
SHOW VARIABLES LIKE 'completion_type';
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| completion_type | NO_CHAIN |
+-----------------+----------+
completion_type = 0: 默认值,执行 commit 后不会自动开启新的事务。
completion_type = 1: 执行 commit 时,相当于执行 COMMIT AND CHAIN,自动开启一个相同隔离级别的事务。
completion_type = 2: 执行 commit 时,相当于执行 COMMIT AND RELEASE,提交事务后自动断开服务器连接。
三、事务并发异常
在实际产线环境下,可能会存在大规模并发请求的情况,如果没有妥善的设置事务的隔离级别,就可能导致一些异常情况的出现,最常见的几种异常为脏读(Dirty Read)、幻读(Phantom Read)
和不可重复读(Unrepeatable Read)。
1、脏读
脏读指一个事务访问到了另一个事务未提交的数据,如下过程:
假设 a 的值为 1,事务 2 把 a 改为 2,此时事务还未提交
在这个时候,事务 1 读取 a,读得 a 的值为 2,事务 1 读取完成
结果事务 2 回滚了对 a 的修改(或者是未 commit),于是 a 的值变回 1
这就导致事实上 a 的值为 1,但是事务 1 取得的结果为 2,所以事务 1 读到了脏数据,发生脏读
2、不可重复读
不可重复读指一个事务多次读取同一数据的过程中,数据值 内容 发生了改变,导致没有办法读到相同的值,描述的是针对同一条数据 update/delete 的现象,如下过程:
事务 1 读取 a,此时 a = 1
此时事务 2 将 a 修改为 2,并成功提交,改动生效
事务 1 又一次读取 a,此时 a = 2
事务 1 在同一个事务里面两次读取同一个值,数据值内容却发生了改变,发生不可重复读
3、幻读
幻读指一个事务多次读取同一数据的过程中,数据 条数 发生了改变,仿佛产生了幻觉,描述的是针对全表 insert/delete 的现象,如下过程:
事务 1 第一次读取数量,得到 10 条数据
此时事务 2 插入了一条数据并成功提交,改动生效,数据变成 11 条
事务 1 再次读取数量,得到 11 条数据,对事务 1 而言莫名其妙的多了一条,好像产生幻觉了一样,发生幻读
四、事务隔离级别
串行化的事务处理方式当然是最安全的,但是串行无法满足数据库高并发访问的需求,作为妥协,有时不得不降低数据库的隔离标准来换取事务的并发能力,通过在可控的范围内牺牲正确性来换取效率的提升,这种权衡通过事务的隔离级别来实现。
数据库有 4 种事务隔离级别,由低到高依次为 读未提交 Read Uncommitted
、读已提交 Read Committed
、可重复读 Repeatable Read
、串行化 Serializable
。
(1)读未提交 Read Uncommitted
允许读取未提交的内容,这种级别下的查询不会加锁,因此脏读、不可重复读、幻读都有可能发生。
(2)读已提交 Read Committed
只允许读取已提交的内容,这种级别下的查询不会发生脏读,因为脏数据属于未提交的数据,所以不会被读取,但是依然有可能发生不可重复读和幻读。
(3)可重复读 Repeatable Read (MySQL 的默认隔离级别)
使用行级锁来保证一个事务在相同查询条件下两次查询得到的数据结果一致,可以避免脏读和不可重复读,但是没有办法避免幻读。
(4)串行化 Serializable
使用表级锁来保证所有事务的串行化,可以防止所有的异常情况,但是牺牲了系统的并发性。
四种隔离级别中上述三种异常情况的容忍度如下(代表允许,
代表禁止):
查看隔离级别的命令为:
SHOW VARIABLES LIKE 'transaction_isolation';
# 或者
SELECT @@global.tx_isolation, @@tx_isolation;
第二种方式可以查看全局和当前会话的隔离级别。
设置隔离级别的命令为:
# 将当前会话的隔离级别设为读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
# 将全局的隔离级别设为读未提交
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
来源:https://blog.csdn.net/wallace_www/article/details/118768540


猜你喜欢
- 下面是代码class GroupInfos(models.Model): uid = models.AutoField(primary_ke
- API的应用通常会处理json数据,刚好今天看到了json字符串和python字符串的区别,放一段代码,区别一下子就看出来,的确json 库
- 只是做笔记,没什么!! --创建测试表 CREATE TABLE [dbo].[Student]( [ID] [int] IDENTITY(
- 一、mongodb安装在官网下载适应于自己平台的mongodb,在此安装环境为Windows7-64bit下载完成后直接安装,连续点击nex
- 本文详细描述使用Django 的ORM框架操作PostgreSQL数据库删除不生效问题的定位过程及解决方案,并总结使用ORM框架操作数据库不
- 两种写法。如图,4种重合情况和2种不重合情况。第一种写法:-- 时间段 a,b SELECT * FROM table WHER
- 想学习Python的人都会有一个困惑,那就是Python目前有两个版本Python2和Python3,Python2与Python3有何区别
- 本文实例讲述了python日期相关操作。分享给大家供大家参考,具体如下:用 Python 做项目时,经常会遇到与日期转换相关,日期计算相关的
- 直观感受几种常用排序算法,具体内容如下1 快速排序介绍:快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n
- 看这篇文章前强烈建议你看看上一篇python实现梯度下降法:一、为什么要提出随机梯度下降算法注意看梯度下降法权值的更新方式(推导过程在上一篇
- 前言今天给大家分享一下刷到的关于数值处理的算法题。虽然题目比较简单但是问题的处理方式值得我们学习。小学生算术涉及到加法进位、阶乘精确值用于计
- 目的测试一个对象是否是字符串方法Python的字符串的基类是basestring,包括了str和unicode类型。一般可以采用以下方法:d
- 正在看的ORACLE教程是:Oracle9i取得建表和索引的DDL语句。我们都知道在9i之前,要想获得建表和索引的语句是一件很麻烦的事。我们
- 一、python图形界面tk之滚动文本框的实现示例使用python的tkinter库实现滚动文本框的方式,目前我知道的有两种,一
- python3.6.2环境安装配置图文教程,具体如下一、需要下载的软件》python3.6.2.exe (也可以选择更新的版本) ----
- 本文实例讲述了Python表示矩阵的方法。分享给大家供大家参考,具体如下:在c语言中,表示个“整型3行4列”的矩阵,可以这样声明:int&n
- 额……首先呢说说这个标题吧,实在不知道叫什么好,因为这个demo呢其实一个艾文王今天中午给丢给我一个图。他说这个是一个面试题,给我看看。这样
- 在使用pycharm开发工具连接mysql数据库时提示错误,信息如下:Server returns invalid timezone. Go
- 前言Python用做数据处理还是相当不错的,如果你想要做爬虫,Python是很好的选择,它有很多已经写好的类包,只要调用,即可完成很多复杂的
- 虽然Python被说成是一种解释型语言,但是实际上,Python源程序要先经过编译,然后才能运行。与Java语言类似,Python源程序编译