MySQL学习笔记-事务相关话题
事务机制
事务(Transaction)是数据库区别于文件系统的重要特性之一。事务会把数据库从一种一致状态转换为另一个种一致状态。在数据库提交工作时,可以确保其要么所有修改都已经保存了,要么所有修改都不保存。
- 原子性(atomicity)
- 一致性(consistency)
- 隔离性(isolation)
- 持久性(durability)
事务一旦提交,其结果就是永久性的。即使发生宕机等故障,数据库也能将数据恢复。
在MySQL命令行的默认设置下,事务都是自动提交的,即执行SQL语句后就会马上执行COMMIT操作。因此开始一个事务,必须使用BEGIN、START TRANSACTION,或者执行SET AUTOCOMMIT=0,以禁用当前会话的自动提交。
以下为事务控制语句:
- START TRANSACTION | BEGIN:显示地开启一个事务。
- COMMIT:提交你的事务,并使得已对数据库做的所有修改成为永久性的。同时写入undo log,将日志缓冲刷新到redo log
- ROLLBACK:回滚结束事务,并撤销正在进行的所有未提交的修改。同时取出redo log。
- SAVEPOING identifier:SAVERPOINT允许你在事务中创建一个保存点,当没有一个保存点执行这句话时,会抛出异常。(以下语句没用过,只能做知识搬运工咯)
- RELEASE SAVERPOINT identifier:删除一个事务的保存点,当没有一个保存点执行这句话时,会抛出一个异常。
- ROLLBACK TO [SAVEPOINT] identifier:这个语句与SAVEPOINT一起用。可以把事务回归到标记点,而不回滚到此标记点之前的任何工作。
- SET TRANSACTION:这个语句用来设置事务的隔离级别。InnoDB存储引擎提供的事务隔离级别有:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE。
隐式提交的SQL语句
以下这些SQL语句会产生一个隐式的提交操作,即执行完这些语句后,会有一个隐式的COMMIT操作。
- DDL语句:ALTER DATABASE...UPGRADE DATA DIRECTORY NAME........
- 用来隐式的修改mysql架构的操作:CREATE USER、DROP USER、GRANT、RENAME USER、REVOKE、SET PASSWORD。
- 管理语句:ANALYZE TABLE、CACHE INDEX、CHECK TABLE、LOAD INDEX INTO CACHE、OPTIMIZE TABLE 、REPAIR TABLE。
在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。数据库锁,也是为了构建这些隔离级别存在的。SQL标准定义的四个隔离级别为:
- 未提交读(READ UNCOMMITTED):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据;
- 提交读(READ COMMITTED):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读);
- 可重复读(REPEATABLE READ):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读;
- 串行读(SERIALIZABLE):InnoDB存储引擎会对每个SELECT语句后自动加上LOCK IN SHARE MODE,即给每个读取操作加一个共享锁,因此在这个事务隔离级别下,读占用锁了,一致性的非锁定读不再予以支持,一般不再本地事务中使用SERIALIZBLE的隔离级别,SERIALIZABLE的事务隔离级别主要用于InnoDB存储引擎的分布式事务。
隔离级别vs读现象(Isolation Levels vs Read Phenomena)
隔离级别 |
脏读(Dirty Read) |
不可重复读(NonRepeatable Read) |
幻读(Phantom Read) |
未提交读(Read uncommitted) | ![]() |
![]() |
![]() |
已提交读(Read committed) |
![]() |
![]() |
![]() |
可重复读(Repeatable read) |
![]() |
![]() |
![]() |
可串行化(Serializable) |
![]() |
![]() |
![]() |
隔离级别vs 锁持续时间(Isolation Levels vs Lock Duration)


隔离级别 |
写操作 |
读操作 |
范围操作 (...where...) |
未提交读(Read uncommitted) |
![]() |
![]() |
![]() |
已提交读(Read committed) |
![]() |
![]() |
![]() |
可重复读(Repeatable read) |
![]() |
![]() |
![]() |
可串行化(Serializable) |
![]() |
![]() |
![]() |
查看当前会话的事务隔离级别命令:
select @@tx_isolation;
查看全局事务隔离级别命令:
select @@global.tx_isolation;



在这个例子中,事务2提交成功,因此他对id为1的行的修改就对其他事务可见了。但是事务1在此前已经从这行读到了另外一个“age”的值。在可序列化(SERIALIZABLE)和可重复读(REPEATABLE READS)的隔离级别,数据库在第二次SELECT请求的时候应该返回事务2更新之前的值。在提交读(READ COMMITTED)和未提交读(READ UNCOMMITTED),返回的是更新之后的值,这个现象就是不可重复读(non-repeatable read)。
有两种策略可以避免不可重复读(non-repeatable read)。一个是要求事务2延迟到事务1提交或者回滚之后再执行。这种方式实现了T1, T2 的串行化调度。串行化调度可以支持可重复读(repeatable reads)。
另一种策略是多版本并发控制。为了得到更好的并发性能,允许事务2先提交。但因为事务1在事务2之前开始,事务1必须在其开始执行时间点的数据库的快照上面操作。当事务1最终提交时候,数据库会检查其结果是否等价于T1, T2串行调度。如果等价,则允许事务1提交,如果不等价,事务1需要回滚并抛出个串行化失败的错误。
使用基于锁的并发控制,在可重复读(REPEATABLE READS)的隔离级别中,ID=1的行会被锁住,在事务1提交或回滚前一直阻塞语句2的执行。在提交读(READ COMMITTED)的级别,语句1第二次执行,age已经被修改了。
在多版本并发控制机制下,可序列化(SERIALIZABLE)级别,两次SELECT语句读到的数据都是事务1开始的快照,因此返回同样的数据。但是,如果事务1试图UPDATE这行数据,事务1会被要求回滚并抛出一个串行化失败的错误。
在提交读(READ COMMITTED)隔离级别,每个语句读到的是语句执行前的快照,因此读到更新前后不同的值。在这种级别不会有串行化的错误(因为这种级别不要求串行化),事务1也不要求重试。

不可重复读和脏读的区别
不可重复读和幻读的区别
很多人容易搞混不可重复读和幻读,确实这两者有些相似。但不可重复读重点在于update和delete,而幻读的重点在于insert。
如果使用锁机制来实现这两种隔离级别,在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复读了。但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会发现莫名其妙多了一条之前没有的数据,这就是幻读,不能通过行锁来避免。需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。
所以说不可重复读和幻读最大的区别,就在于如何通过锁机制来解决他们产生的问题。
上文说的,是使用悲观锁机制来处理这两种问题,但是MySQL、ORACLE、PostgreSQL等成熟的数据库,出于性能考虑,都是使用了以乐观锁为理论基础的MVCC(多版本并发控制)来避免这两种问题。
MySQL学习笔记-事务相关话题的更多相关文章
- MySQL学习笔记-锁相关话题
在事务相关话题中,已经提到事务隔离性依靠锁机制实现的.在本篇中围绕着InnoDB与MyISAM锁机制的不同展开,进而描述锁的实现方式,多种锁的概念,以及死锁产生的原因. Mysql常用存储引擎的锁 ...
- MySQL学习笔记-数据库文件
数据库文件 MySQL主要文件类型有如下几种 参数文件:my.cnf--MySQL实例启动的时候在哪里可以找到数据库文件,并且指定某些初始化参数,这些参数定义了某种内存结构的大小等设置,还介绍了参数类 ...
- MySQL学习笔记-数据库内存
数据库内存 InnoDB存储引擎内存由以下几个部分组成:缓冲池(buffer pool).重做日志缓冲池(redo log buffer)以及额外的内存池(additional memory pool ...
- MySQL学习笔记-数据库后台线程
数据库后台线程 默认情况下讲述的InnoDB存储引擎,以后不再重复声明.后台线程有7个--4个IO thread,1个master thread,1个锁监控线程,1个错误监控线程.IO thread的 ...
- MySQL学习笔记-cache 与 buffer
Cache和Buffer是两个不同的概念,简单的说,Cache是加速"读",而 buffer是缓冲"写",前者解决读的问题,保存从磁盘上读出的数据,后者是解决写 ...
- MySQL学习笔记-大纲
软件程序性能测试在之前<品味性能之道>系列中已经大量提到,讲解了很多测试方法.测试观念.测试思想等等.最近准备深入MySQL进行学习并总结.分别查阅<MySQL性能调优与架构设计&g ...
- MySQL学习笔记-MySQL体系结构总览
MySQL体系结构总览 不管是用哪种数据库,了解数据库的体系结构都是极为重要的.MySQL体系结构主要由数据库和数据库实例构成. 数据库:物理操作系统文件或者其它文件的集合,在mysql中,数据库文件 ...
- MySQL学习笔记一
MySQL 学习笔记 一 一.数据库简单介绍 1. 按照数据库的发展时间顺序,主要出现了以下类型数据库系统: Ø 网状型数据库 Ø 层次型数据库 Ø 关系型数据库 Ø 面向对象数据库 上面4中数据库系 ...
- 数据库MySQL学习笔记高级篇
数据库MySQL学习笔记高级篇 写在前面 学习链接:数据库 MySQL 视频教程全集 1. mysql的架构介绍 mysql简介 概述 高级Mysql 完整的mysql优化需要很深的功底,大公司甚至有 ...
随机推荐
- 阿里大于发送短信(java)
一.短信签名设置 1.短信签名是什么? 签名是在短信内容开始或者末尾跟的品牌或者应用名称,设置签名有一下几个好处:增加品牌的曝光度,增强用户的记忆让用户能更清楚的知道正在使用的应用. 2.签名可不可以 ...
- windows下配置pymysql
可以直接pip安装 pip install pyMysql
- Codeforces Round #499 (Div. 2) C Fly题解
题目 http://codeforces.com/contest/1011/problem/C Natasha is going to fly on a rocket to Mars and retu ...
- 【C++】SGI-STL空间配置器
第一级配置器是对C的内存分配函数malloc,free,realloc的简单封装,用来分配大于128bytes的区块. 第二级配置器管理16个free-lists链表,各自管理8-128bytes的小 ...
- js增减日期
参考 https://www.cnblogs.com/gmq-sh/p/5194706.html date.setDate(date.getDate() + 3);
- NumPy 统计函数
NumPy 统计函数 NumPy 提供了很多统计函数,用于从数组中查找最小元素,最大元素,百分位标准差和方差等. 函数说明如下: numpy.amin() 和 numpy.amax() numpy.a ...
- 01背包 hdu1864
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1864 注意事项: 在这里所有输入的价格都是两位小数(题目没说,看论坛才知道的). 这里单项价格不能超过 ...
- Gym - 101911B Glider(前缀和+二分)
传送门:点我 A plane is flying at a constant height of hh meters above the ground surface. Let's consider ...
- 《centos系列》ubuntu终端链接centos服务器
首先你得知道centos的账户密码:如果你不知道可以直接在centos下使用root用户: passwd 用户名 直接更新用户的密码. 然后在ubuntu终端(前提是已经安装了ssh): ssh ad ...
- 2017-2018-2 20165315 实验三《敏捷开发与XP实践》实验报告
2017-2018-2 20165315 实验三<敏捷开发与XP实践>实验报告 一.编码标准 编写代码一个重要的认识是"程序大多时候是给人看的",编程标准使代码更容易阅 ...