MySQL 什么是事务?
该文为《 MySQL 实战 45 讲》的学习笔记,感谢查看,如有错误,欢迎指正
一、事务简介
事务就是为了保证一组数据库操作,要么全部成功,要么全部失败。
事务是在引擎层实现的,也就是说并不是所有引擎都可以使用事务,MyISAM 就不支持事务,这也是为什么会被 InnoDB 取代的原因。
说到事务,就不得不说 ACID 特性(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)。
二、ACID 特性
2.1 原子性(Atomicity)
一个事务中的多组操作,要么全部成功,要么全部失败。在事务提交(commit)成功之后,所有的操作都生效,提交失败,所有的操作都会回滚。
2.2 一致性(Consistency)
一个事务执行之前和执行之后数据库都必须处于一致性状态。在事务执行的过程中,只要事务未提交,就不会改变数据库的状态。提交之后事务已完成,此时数据库状态发生变化。
2.3 隔离性(Isolation)
事务在执行过程中,是与外界完全隔离的,即使数据库发生了变更,事务中也获取不到。A 事务对数据库做的变更,在事务未提交之间,数据库中也看不到,B 事务中也看不到。
2.4 持久性(Durability)
事务一旦提交,对数据库的变更就会持久化到磁盘,即使数据库发生异常重启,数据也不会丢失。
三、隔离级别
当数据库出现有多个事务同时执行时,就可能出现脏读,幻读,不可重复读等问题,隔离级别就是为了解决这些问题的。隔离的越严实,效率就越低,并发越低,安全性越高。
隔离级别分为以下 4 种:
读未提交(read uncommitted,RU)
一个事务还未提交时,它做的变更就可以被别的事务看到。读提交(read committed,RC)
事务提交以后,它做的变更才能被其它事务看到。但是在这个事务未提交之前,数据库中发生的变更,这个事务也能看见。可重复度(repeatable read,RR)
事务总是只能看见在启动的那个时刻,数据库的状态。事务未提交之前做的变更,其它事务看不见。事务执行期间,数据库中已经发生的变更,这个事务也看不见。只能看见事务刚启动时刻,数据库的状态。串行化(serializable)
事务对某一行的操作会加锁,“写”会加“写锁”,“读”会加“读锁”,在锁释放掉之前,其它的事务都无法都这一行的记录进行操作。必须等之前的事务执行完毕,释放锁。后面的事务又会重新加锁。
我们通过一个例子来说明一下四种隔离级别具体是怎么体现的。
给出一个建表语句:
mysql> create table T(c int) engine=InnoDB;
mysql> insert into T(c) values(1);
假设有以下两个事务,其中执行的操作如图,从上至下是时间先后顺序:

在四种不同的隔离级别下,V1、V2、V3的值分别为多少呢?我们现在分析一下:
读未提交
读提交下,事务还未提交,做的变更就能被其它事务看见,因此事务 B 修改了值为 2 ,事务 A 可以直接看见。所以V1 = 2,V2 = 2,V3 = 2。读提交(RC)
读提交下,事务在提交之前,做的变更都无法被其它事务看见,但是事务本身可以看到数据库的变更。 因此,事务 B 做了修改以后,事务 A 无法立刻看见,V1 = 1,事务 B 提交以后,事务 A 就可以看到数据库的变更了,因此V2 = 2,V3 = 2。可重复读(RR)
事务总是只能看到在启动的那个时刻,数据库的状态,即在事务未提交之前,自己做的变更别的事务看不见,数据库中的变更自己也看不见。
因此,事务 B 提交之前,A 看不见 B 做的变更,V1 = 1,事务 B 提交以后,数据库的值虽然发生了变更,但是事务 A 还未提交,A 还是只能看到自己在启动时刻,数据库的值(可以理解为数据库有版本,只能看见历史版本)。因此,V2 = 1,事务 A 提交以后,就可以看到数据库的变更了,因此V3 = 2。串行化
串行化是指,事务在操作某一行记录时会加锁,“读”会加“读锁”,“写”会加“写锁”。
事务 A 在启动后,先执行了 1 条查询语句,对这行数据加了“读锁”,这个“读锁”要等事务 A 提交以后,才会释放。因此事务 B 执行查询语句会处于等待锁释放状态。这时候事务 B 会一直等待。因此,V1 = 1,V2 = 1,事务 A 提交之后,“读锁”释放,事务 B 获取该行记录的“读锁”,并更新了数据(又加了一个“写锁”),事务 B 未提交之前,A 再去查数据也需要等待锁释放,事务 B 提交以后,锁释放,A 拿到锁,开始查询数据,因此,V3 = 2。
以上是如何实现的呢?
四、事务隔离的实现原理
数据库中会创建一个视图,在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;而“串行化”隔离级别下直接用加锁的方式来避免并行访问。
在 MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。
回滚日志什么时候删除呢,系统中没有比这个回滚日志更早的 read-view 时,这个回日志就会被删除。
因此不建议使用长事务,容易导致回滚日志太多,大量占用存储空间。
五、事务的启动方式
- 显式启动:
begin或start transaction。配套的提交语句是commit,回滚语句是rollback。 - 也可以使用
set autocommit=0,此时不需要显式启动,比如执行了一个select语句就直接启动了事务,但是需要再执行一条commit来提交;
因此建议设置set autocommit=1,此时需要用begin来开启事务,如果觉得多了一次交互,比较麻烦的话,也可以使用commit work and chain,表示提交当前事务,并且再启动一个新的事务,这样就只有一次begin了。
感谢阅读,有兴趣的小伙伴可以关注我的微信公众号DevOps探索之旅,大家一起学习进步

MySQL 什么是事务?的更多相关文章
- PHP mysql与mysqli事务详解
官方对PHP连接到MySQL数据库服务器的三种主要的API简介如下: http://php.net/manual/zh/mysqli.overview.php PHP mysql与mysqli事务详解 ...
- 【MySQL】漫谈MySQL中的事务及其实现
最近一直在做订单类的项目,使用了事务.我们的数据库选用的是MySQL,存储引擎选用innoDB,innoDB对事务有着良好的支持.这篇文章我们一起来扒一扒事务相关的知识. 为什么要有事务? 事务广泛的 ...
- MySQL数据库的事务管理
当前在开发ERP系统,使用到的数据库为Mysql.下面介绍下如何开启事务,以及事务隔离的机制 : 1. 检查当前数据库使用的存储引擎. show engines; 2. 修改前my.ini中的文件如下 ...
- MySQL存储过程之事务管理
原文链接:http://hideto.iteye.com/blog/195275 MySQL存储过程之事务管理 ACID:Atomic.Consistent.Isolated.Durable 存储程序 ...
- MySQL数据库分布式事务XA优缺点与改进方案
1 MySQL 外部XA分析 1.1 作用分析 MySQL数据库外部XA可以用在分布式数据库代理层,实现对MySQL数据库的分布式事务支持,例如开源的代理工具:ameoba[4],网易的DDB,淘宝的 ...
- 漫谈MySql中的事务
最近一直在做订单类的项目,使用了事务.我们的数据库选用的是MySql,存储引擎选用innoDB,innoDB对事务有着良好的支持.这篇文章我们一起来扒一扒事务相关的知识. 为什么要有事务? 事务广泛的 ...
- mysql中不同事务隔离级别下数据的显示效果--转载
事务是一组原子性的SQL查询语句,也可以被看做一个工作单元.如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查询语句因为崩溃或其他原因而无法执行,那么所有的语句就都 ...
- 浅谈mysql中不同事务隔离级别下数据的显示效果
事务的概念 事 务是一组原子性的SQL查询语句,也可以被看做一个工作单元.如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查 询语句因为崩溃或其他原因而无法执行,那 ...
- MySql中的事务嵌套
1.Mysql中的事务必须是InnoDB.Berkeley DB引擎,myisam不支持. 2.Mysql是不支持嵌套事务的,开启了一个事务的情况下,再开启一个事务,会隐式的提交上一个事务. 3.My ...
- MySQL中Procedure事务编写基础笔记
原文:MySQL中Procedure事务编写基础笔记 目录: 一.PROCEDURE: 二.CREATE PROCEDURE基本语法: 三.PROCEDURE小进阶 3.1.基本的DECLARE语 ...
随机推荐
- IO系统-标准C的I/O和文件I/O
1.标准C的I/O 1.1常用函数和结构体 char *fgets(char *s, int size, FILE *stream); //整行输入 int printf(const char *fo ...
- xpath写法大全(适用于selenium、robotframework)
1.//input[contains(@id, 'txttags')] 定位出来是个ID,但是ID后面的“102”是个随机数,所以用定位ID的方法就不行了,用firepath生成的xpath也会包括这 ...
- HTML中CSS引用——选择器的使用
一.元素选择器 1.书写格式:标记名{/*生命块*/} 2.所有与该标记匹配的元素,都将应用声明块中的规则 二.类选择器 1.书写格式:.类名{/*声明块*/} ...
- PlayCanvas PBR材质shader代码分析(vertex shader)
顶点shader主要对顶点坐标变换,将顶点坐标从local->world->view->clip 空间变换 local空间:模型物体坐标系 world空间:世界空间坐标系 view空 ...
- JS-07-函数
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 移动端ui框架
https://blog.csdn.net/Robin_star_/article/details/81810197
- PTA 练习 7-24 喊山 (30 分)
7-24 喊山 (30 分) 喊山,是人双手围在嘴边成喇叭状,对着远方高山发出"喂-喂喂-喂喂喂--"的呼唤.呼唤声通过空气的传递,回荡于深谷之间,传送到人们耳中,发出约定俗成的& ...
- C++基类和派生类的析构函数
1.派生类也不能继承基类的析构函数. 2.与构造函数不同的是,在派生类的析构函数中不用显式地调用基类的析构函数,因为每个类只有一个析构函数,编译器知道如何选择,无需程序员干涉. 3.构造函数和虚构函数 ...
- (5千字)由浅入深讲解动态规划(JS版)-钢条切割,最大公共子序列,最短编辑距离
斐波拉契数列 首先我们来看看斐波拉契数列,这是一个大家都很熟悉的数列: // f = [1, 1, 2, 3, 5, 8] f(1) = 1; f(2) = 1; f(n) = f(n-1) + f( ...
- copy constructor和copy assignment operator的区别
拷贝构造函数(copy constructor)被用来以一个对象来初始化同类型的另一个对象,拷贝赋值运算符(copy assignment operator)被用来将一个对象中的值拷贝到同类型的另一个 ...