理解MySQL数据库事务-隔离性
Transaction事务是指一个逻辑单元,执行一系列操作的SQL语句。
事务中一组的SQL语句,要么全部执行,要么全部回退。在Oracle数据库中有个名字,叫做transaction ID
在关系型数据库中,事务必须ACID的特性。
- 原子性,事务中的操作,要不全部执行,要不都不执行
- 一致性,事务完成前后,数据的必须保持一致。
- 隔离性,多个用户并发访问数据库时,每一个用户开启的事务,相互隔离,不被其他事务的操作所干扰。
- 持久性,事务一旦commit,它对数据库的改变是持久性的。
目前重点讨论隔离性。数据库一共有四个隔离级别
未提交读(RU,Read Uncommitted)。它能读到一个事物的中间状态,不符合业务中安全性的保证,违背 了ACID特性,存在脏读的问题,基本不会用到,可以忽略
提交读(RC,Read Committed)。顾名思义,事务提交之后,那么我们可以看到。这是一种最普遍的适用的事务级别。我们生产环境常用的使用级别。
可重复读(RR,Repeatable Read)。是目前被使用得最多的一种级别。其特点是有GAP锁,目前还是默认级别,这个级别下会经常发生死锁,低并发等问题。
可串行化,这种实现方式,其实已经是不是多版本了,而是单版本的状态,因为它所有的实现都是通过锁来实现的。
因此目前数据库主流常用的是RC和RR隔离级别。
隔离性的实现方式,我们通常用Read View表示一个事务的可见性。
RC级别,事务可见性比较高,它可以看到已提交的事务的所有修改。因此在提交读(RC,Read Committed)隔离级别下,每一次select语句,都会获取一次Read View,得到数据库最新的事务提交状态。因此对于数据库,并发性能也最好。
RR级别,则不是。它为了避免幻读和不可重复读。保证在一个事务内前后数据读取的一致。其可见性视图Read View只有在自己当前事务提交之后,才会更新。
那如何保证数据的一致性?其核心是通过redo log和undo log来保证的。
而在数据库中,为了实现这种高并发访问,就需要对数据库进行多版本控制,通过事务的可见性来保证事务看到自己想看到的那个数据版本(或者是最新的Read View亦或者是老的Read View)。这种技术叫做MVCC
多版本是如何实现的?通过undo日志来保证。每一次数据库的修改,undo日志会存储之前的修改记录值。如果事务未提交,会回滚至老版本的数据。其MVCC的核心原理,以后详谈
举例论证:
## 开启事务
MariaDB [scott]> begin;
Query OK, 0 rows affected (0.000 sec)
##查看当前的数据
MariaDB [scott]> select * from dept;
+--------+------------+----------+
| deptno | dname | loc |
+--------+------------+----------+
| 10 | ACCOUNTING | beijing |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | beijing |
| 50 | security | beijing |
| 60 | security | nanchang |
+--------+------------+----------+
6 rows in set (0.001 sec)
##更新数据
MariaDB [scott]> update dept set loc ='beijing' where deptno = 20;
Query OK, 1 row affected (0.001 sec)
## 其行记录| 20 | RESEARCH | DALLAS |已经被放置在undo日志中,目前最新的记录被改为'beijing':
MariaDB [scott]> select * from dept;
+--------+------------+----------+
| deptno | dname | loc |
+--------+------------+----------+
| 10 | ACCOUNTING | beijing |
| 20 | RESEARCH | beijing |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | beijing |
| 50 | security | beijing |
| 60 | security | nanchang |
+--------+------------+----------+
##事务不提交,回滚。数据回滚至老版本的数据。
MariaDB [scott]> rollback;
Query OK, 0 rows affected (0.004 sec)
MariaDB [scott]> select * from dept;
+--------+------------+----------+
| deptno | dname | loc |
+--------+------------+----------+
| 10 | ACCOUNTING | beijing |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | beijing |
| 50 | security | beijing |
| 60 | security | nanchang |
+--------+------------+----------+
6 rows in set (0.000 sec)
因为MVCC,让数据库有了很强的并发能力。随着数据库并发事务处理能力大大增强,从而提高了数据库系统的事务吞吐量,可以支持更多的用户并发访问。但并发访问,会出现带来一系列问题。如下:
| 数据库并发带来的问题 | 概述解释 |
|---|---|
| 脏读(Dirty Reads) | 当一个事务A正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务B也访问这同一个数据,如不控制,事务B会读取这些"脏"数据,并可能做进一步的处理。这种现象被称为"脏读"(Dirty Reads) |
| 不可重复读(Non-Repeatable Reads) | 指在一个事务A内,多次读同一数据。在这个事务还没有结束时,另外一个事务B也访问该同一数据。那么,在事务A的两次读数据之间,由于第二个事务B的修改,那么第一个事务两次读到的的数据可能是不一样的 。出现了"不可重复读"(Non-Repeatable Reads)的现象 |
| 幻读(Phantom Reads) | 指在一个事务A内,按相同的查询条件重新检索以前检索过的数据,同时发现有其他事务插入了数据,其插入的数据满足事务A的查询条件。因此查询出了新的数据,这种现象就称为"幻读"(Phantom Reads) |
隔离级别和上述现象之间的联系。
隔离级别有:未提交读(RU,Read Uncommitted),提交读(RC,Read Committed),可重复读(RR,Repeatable Read),可串行化(Serializable)
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 未提交读(RU,Read Uncommitted) | 可能 | 可能 | 可能 |
| 提交读(RC,Read Committed) | 不可能 | 可能 | 可能 |
| 可重复读(RR,Repeatable Read) | 不可能 | 不可能 | 可能 (间隙锁解决) |
| 可串行化(Serializable) | 不可能 | 不可能 | 不可能 |
实验环节
举例在隔离级别RR和RC下,说明“不可重复读”问题。
MySQL的默认级别是Repeatable Read,如下:
MariaDB [(none)]> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set (0.000 sec)
这里修改当前会话级别为Read Committed
MariaDB [scott]> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.001 sec)
MariaDB [scott]> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set (0.000 sec)
在隔离级别已提交读(RC,Read Committed)下,出现了不可重复读的现象。在事务A中可以读取事务B中的数据。

在隔离级别可重复读(RR,Repeatable Read),不会出现不可重复读现象,举例如下:

举例说明“幻读”的现象。
行锁可以防止不同事务版本的数据在修改(update)提交时造成数据冲突的问题。但是插入数据如何避免呢?
在RC隔离级别下,其他事务的插入数据,会出现幻读(Phantom Reads)的现象。

而在RR隔离级别下,会通过Gap锁,锁住其他事务的insert操作,避免"幻读"的发生。

因此,在MySQL事务中,锁的实现方式与隔离级别有关,如上述实验所示。在RR隔离级别下,MySQL为了解决幻读的问题,已牺牲并行度为代价,通过Gap锁来防止数据的写入。这种锁,并行度差,冲突多。容易引发死锁。
目前流行的Row模式可以避免很多冲突和死锁问题,因此建议数据库使用ROW+RC(Read Committed)模式隔离级别,很大程度上提高数据库的读写并行度,提高数据库的性能。
理解MySQL数据库事务-隔离性的更多相关文章
- Mysql数据库事务隔离级别
事务(transaction)是数据库管理系统的执行单位,可以是一个数据库操作(如Select操作)或者是一组操作序列.事务ACID属性,即原子性(Atomicity).一致性(Consistency ...
- mysql数据库——事务隔离级别
四种隔离级别: 一:READ UNCOMMITTED(未提交读) 事务可以读取其他事务未提交的数据,称为脏读 二:READ COMMITTED(提交读) 一个事务开始时,只能"看见" ...
- 理解MySQL数据库事务
1. 什么是事务处理? 事务处理是一种机制,它是用来管理必须成批执行的mysql操作.来保证数据库不完整的操作结果. 2. 为什么要使用事务处理? 在使用mysql操作数据的过程中,如果只是简单的中小 ...
- mysql事务之一:MySQL数据库事务隔离级别(Transaction Isolation Level)及锁的实现原理
一.数据库隔离级别 数据库隔离级别有四种,应用<高性能mysql>一书中的说明: 然后说说修改事务隔离级别的方法: 1.全局修改,修改mysql.ini配置文件,在最后加上 1 #可选参数 ...
- MySQL数据库事务隔离级别(Transaction Isolation Level)
转自: http://www.cnblogs.com/zemliu/archive/2012/06/17/2552301.html 数据库隔离级别有四种,应用<高性能mysql>一书中的 ...
- mysql数据库事务隔离原理
今天在学习JDBC的时候看到了关于MySQL的事务的隔离级别的问题,感觉内容挺高级的,所以记录一篇文章,以备后面使用. 数据库隔离级别有四种,应用<高性能mysql>一书中的说明: 然后说 ...
- [转]MySQL 数据库事务隔离级别
然后说说修改事务隔离级别的方法: 1. 全局修改,修改 mysql.ini 配置文件,在最后加上 1 #可选参数有:READ-UNCOMMITTED, READ-COMMITTED, REPEATAB ...
- mysql数据库事务详细剖析
在写之前交代一下背景吧! 做开发也好久了,没怎么整理过知识,现在剖析一下自己对数据库事务的认识,以前用sqlserver,现在转java后又用mysql.oracle.我这块就主要解释一下mysql数 ...
- 跟面试官侃半小时MySQL事务隔离性,从基本概念深入到实现
提到MySQL的事务,我相信对MySQL有了解的同学都能聊上几句,无论是面试求职,还是日常开发,MySQL的事务都跟我们息息相关. 而事务的ACID(即原子性Atomicity.一致性Consiste ...
随机推荐
- linux自启动脚本.sh
while [ 1 ]; do PRO_NUM=`ps -ef | grep "cms$" | grep -v "grep" | wc ...
- cmd 获取当前登录的用户和远程连接的用户
打开cmd 执行 quser 可以看到我有两个 会话 带> 是我当前的会话 rdp 是远程连接的会话 console 是本机操作 可以知道谁在连接你 状态是 唱片 就是未连接的意思 ...
- 玩转OneNET物联网平台之MQTT服务① —— OneNetMqtt全方位调试
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- java的数制转换(详解,全!)
对于进制转换,c/c++要用到辗转相除,不仅浪费时间,还造成代码量繁多,而任意之间的进制转换还需要以十进制为跳板, 先将其他进制的数字转换为十进制,再将十进制转换为其他进制,而java中自带进制转换的 ...
- Java_条件控制与循环控制
条件控制语句: 1. if-else语句 if(条件1){ 代码块1; }else if(条件2){ 代码块2; }else{ 代码块3; } 2. switch语句 switch(变 ...
- Kerberos kinit crontab定时任务不生效的问题解决
问题 有这样一个定时任务 1 */12 * * * kinit -kt xxxxxx.keytab principle 这样写每天 12点,执行一次. 但是服务器的应用程序报错: GSS initia ...
- 基于appium实现的线性代码引用unittest单元测试框架
在前段时间,分享了几篇关于appium基础的博文,再加上期间也有讲到unittest测试框架,所以今天就来一个专题,在appium+python实现的线性代码基础上,引入unittest框架,使代码更 ...
- 数据结构(三十二)图的遍历(DFS、BFS)
图的遍历和树的遍历类似.图的遍历是指从图中的某个顶点出发,对图中的所有顶点访问且仅访问一次的过程.通常有两种遍历次序方案:深度优先遍历和广度优先遍历. 一.深度优先遍历 深度优先遍历(Depth_Fi ...
- SpringBoot1.x与监控(六)
由于2.x和1.x的监控不一样,此处先讲1.x 一 SpringBoot1.x监控 pom.xml <dependency> <groupId>org.springframew ...
- SpringBoot系列之@Value和@ConfigurationProperties
继上一篇博客SpringBoot系列之YAML配置用法之后,再写一篇@Value.@ConfigurationProperties的对比博客 这两个主键都是可以获取配置文件属性的,不过是有比较大的区别 ...