【眼见为实】自己动手实践理解数据库READ UNCOMMITED && SERIALIZABLE
我们自己通过Sql语句模拟场景来验证Mysql InnoDB引擎事务各级隔离级别对应封锁协议的工作机制。在开始实践之前我们需要做一些准备工作。
准备工作
①准备测试表和测试数据
需要建立一个测试数据表,建表语句:
create table users
(
id int auto_increment not null primary key,
name char(10) not null,
state int not null
);
然后插入一条测试数据:
insert into users values(1,'swj',0);
②关闭数据库事务自动提交
# 0为关闭 1为开启
SET autocommit = 0;
设置完成后我们可以通过下列语句查看是否关闭了自动提交。
show variables like 'autocommit';
OFF关闭无误。

③设置InnoDB存储引擎隔离级别
首先我们可以使用下面的语句分别查看数据库的系统级隔离级别和会话级隔离级别。
select @@global.tx_isolation,@@tx_isolation;

这也说明了MySql数据库默认使用的隔离级别是可重复读(REPEATABLE-READ)。
我们可以使用下面的语句设置隔离级别。隔离级别有READ UNCOMMITTED | **READ COMMITTED **| REPEATABLE READ | SERIALIZABLE四种。
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
[READ UNCOMMITTED]
首先设置数据库隔离级别为读未提交(READ UNCOMMITTED):
set global transaction isolation level READ UNCOMMITTED ;
set session transaction isolation level READ UNCOMMITTED ;
[READ UNCOMMITTED]能解决的问题
我们来看一下为什么[READ UNCOMMITTED]能解决丢失更新的问题:
事务1:
START TRANSACTION;
① UPDATE users SET state=state+1 WHERE id=1;
② SELECT sleep(10);
COMMIT;
事务2:
START TRANSACTION;
① UPDATE users SET state=state+1 WHERE id=1;
COMMIT;
事务1先于事务2执行。
事务1的执行信息:
[SQL 1]START TRANSACTION;
受影响的行: 0
时间: 0.000s
[SQL 2]
UPDATE users SET state=state+1 WHERE id=1;
受影响的行: 1
时间: 0.001s
[SQL 3]
SELECT sleep(10);
受影响的行: 0
时间: 10.000s
[SQL 4]
COMMIT;
受影响的行: 0
时间: 0.068s
事务2的执行信息:
[SQL 1]START TRANSACTION;
受影响的行: 0
时间: 0.000s
[SQL 2]
UPDATE users SET state=state+1 WHERE id=1;
受影响的行: 1
时间: 8.787s
[SQL 3]
COMMIT;
受影响的行: 0
时间: 0.098s
执行结果:

结论:读未提交[READ UNCOMMITTED]隔离级别可以解决丢失更新的问题。
分析:因为读未提交[READ UNCOMMITTED]隔离级别对应数据库的一级封锁协议。一级封锁协议在修改数据之前对其加X锁,直到事务结束释放X锁。读数据不加锁。因为事务1先执行修改,修改前申请持有X锁,事务结束释放X锁。持锁时间段为[SQL 2]开始前到[SQL 4]结束,持锁时间大约为10.069s。事务2也执行修改操作,修改前也申请持有X锁。因为事务1执行更新操作等待10秒才会提交释放锁,所以事务2申请持锁需要等待,直到事务1结束才能获取到锁的持有权进行修改。事务2的执行信息中的[SQL 2]时间为8.787s(因为手速原因存在误差,实际应该为10秒左右)就能说明这一点。这样对同一数据的修改会变成串行化的修改,所以不会出现因为并发只进行一次+1的情况,也就不会出现丢失修改的问题。
[READ UNCOMMITTED]不能解决的问题
读未提交,顾名思义,一个事务可以读到另一个事务没有提交的内容,如果另一个事务进行回滚就会产生脏读。
我们来模拟一下脏读:
事务1:
START TRANSACTION;
① UPDATE users SET state=1 WHERE id=1;
② SELECT sleep(5);
ROLLBACK;
事务2:
START TRANSACTION;
① SELECT * FROM users WHERE id=1;
COMMIT;
事务1先于事务2执行。
事务1的执行信息:
[SQL 1]START TRANSACTION;
受影响的行: 0
时间: 0.000s
[SQL 2]
UPDATE users SET state=1 WHERE id=1;
受影响的行: 1
时间: 0.002s
[SQL 3]
SELECT sleep(5);
受影响的行: 0
时间: 5.000s
[SQL 4]
ROLLBACK;
受影响的行: 0
时间: 0.067s
事务2的执行信息:
[SQL 1]START TRANSACTION;
受影响的行: 0
时间: 0.001s
[SQL 2]
SELECT * FROM users WHERE id=1;
受影响的行: 0
时间: 0.001s
[SQL 3]
COMMIT;
受影响的行: 0
时间: 0.000s
事务2的执行结果:

事务1和事务2都执行结束时,再进行一次查询的结果:

结论:读未提交[READ UNCOMMITTED]隔离级别解决不了脏读的问题,更解决不了不可重复读的问题。
分析:因为读未提交[READ UNCOMMITTED]隔离级别对应数据库的一级封锁协议。一级封锁协议在修改数据之前对其加X锁,直到事务结束释放X锁。读数据不加锁。因为事务1先执行修改,修改前申请持有X锁,持锁时间段为[SQL 2]开始前到[SQL 4]结束,持锁时间大约为5.069s。事务2执行读操作,不需要申请持锁,而是直接去磁盘读取数据。读取出的数据是事务1修改后的,而此时事务1回滚,修改的数据被还原,就产生了脏读现象。
[SERIALIZABLE]
这个级别的封锁就很好理解了,读加共享锁,写加排他锁,读写互斥。使用的悲观锁的理论,所有操作串行化执行,数据更加安全,但是并发能力非常差。如果你的业务并发的特别少或者没有并发,同时又要求数据及时可靠的话,可以使用这种模式。
我们重点探究的不是[READ UNCOMMITTED]和[SERIALIZABLE]级别,而是[READ COMMITTED]和[REPEATABLE READ]。如果您对此感兴趣可以看一下后两篇博客。
本文为博主学习感悟总结,水平有限,如果不当,欢迎指正。
如果您认为还不错,不妨点击一下下方的[【推荐】](javascript:void(0)
【眼见为实】自己动手实践理解数据库READ UNCOMMITED && SERIALIZABLE的更多相关文章
- 【眼见为实】自己动手实践理解数据库REPEATABLE READ && Next-Key Lock
[REPEATABLE READ] 首先设置数据库隔离级别为可重复读(REPEATABLE READ): set global transaction isolation level REPEATAB ...
- 【眼见为实】自己动手实践理解数据库READ COMMITTED && MVCC
[READ COMMITTED] 首先设置数据库隔离级别为读已提交(READ COMMITTED): set global transaction isolation level READ COMMI ...
- 【眼见为实】自己动手实践理解REPEATABLE READ && Next-Key Lock
首先设置数据库隔离级别为可重复读(REPEATABLE READ): set global transaction isolation level REPEATABLE READ ; set sess ...
- 【眼见为实】自己动手实践理解READ COMMITTED && MVCC
[眼见为实]自己动手实践理解 READ COMMITTED && MVCC 首先设置数据库隔离级别为读已提交(READ COMMITTED): set global transacti ...
- [转帖]Docker从入门到动手实践
Docker从入门到动手实践 https://www.cnblogs.com/nsky/p/10853194.html dockerfile的图很好呢. 但是自己没有做实验 , 其实知识都挺好. do ...
- 【原创 Hadoop&Spark 动手实践 8】Spark 应用经验、调优与动手实践
[原创 Hadoop&Spark 动手实践 7]Spark 应用经验.调优与动手实践 目标: 1. 了解Spark 应用经验与调优的理论与方法,如果遇到Spark调优的事情,有理论思考框架. ...
- 【原创 Hadoop&Spark 动手实践 9】Spark SQL 程序设计基础与动手实践(上)
[原创 Hadoop&Spark 动手实践 9]SparkSQL程序设计基础与动手实践(上) 目标: 1. 理解Spark SQL最基础的原理 2. 可以使用Spark SQL完成一些简单的数 ...
- 【原创 Hadoop&Spark 动手实践 10】Spark SQL 程序设计基础与动手实践(下)
[原创 Hadoop&Spark 动手实践 10]Spark SQL 程序设计基础与动手实践(下) 目标: 1. 深入理解Spark SQL 程序设计的原理 2. 通过简单的命令来验证Spar ...
- 【原创 Hadoop&Spark 动手实践 6】Spark 编程实例与案例演示
[原创 Hadoop&Spark 动手实践 6]Spark 编程实例与案例演示 Spark 编程实例和简易电影分析系统的编写 目标: 1. 掌握理论:了解Spark编程的理论基础 2. 搭建 ...
随机推荐
- 剑指offer三十四之第一个只出现一次的字符
一.题目 在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置 二.思路 详见代码注释. 三.代码 import java.util. ...
- PCA(主成分分析)和LDA详解
http://www.cnblogs.com/LeftNotEasy/archive/2011/01/08/lda-and-pca-machine-learning.html http://www.c ...
- EJB3 阶段总结+一个EJB3案例 (1)
经过一段时时间的学习,对EJB3的相关知识和jboss8的配置有了大概的了解. 网上对EJB的评论很多,基本都是负面的,都表示EJB太过于沉重,不容易维护.但通过这段时间的学习,私下认为,EJB3在某 ...
- MySQl中的\g和\G
1. \g 在MySQL的sql语句后加上\g,效果等同于加上定界符,一般默认的定界符是分号; 2. \G 在MySQL的sql语句后加上\G,表示将查询结果进行按列打印,可以使每个字段打印到单独的行 ...
- 怎么将一张100KB以上大小的电子图片压缩成30KB以内
不多说,直接上干货! 方法一: 怎么将一张100KB以上大小的电子照片压缩成30KB以内. 先将这张100KB以上大小的电子照片,新建一个word,放入.选中照片,右击,另存为,格式依然还是选择.jp ...
- C#的Equals不区分大小写
代码:System.Windows.Forms.MessageBox.Show("abc".Equals("ABC", StringComparison.Inv ...
- C++中模板与泛型编程
目录 定义一个通用模板 模板特化和偏特化 模板实例化与匹配 可变参数模板 泛型编程是指独立与任何类型的方式编写代码.泛型编程和面向对象编程,都依赖与某种形式的多态.面向对象编程的多态性在运行时应用于存 ...
- Fiddler实现手机抓包——小白入门(转载csdn)
手机用fiddler抓包 电脑最好是笔记本,这样能和手机保持统一局域网内:其他不多说,直接说步骤了. 一.对PC(笔记本)参数进行配置 1. 配置fiddler允许监听到https(fiddle ...
- asdfasdfasdfasdf
- tomcat shutdown.sh结束不了,Could not contact localhost:8005
使用./shutdown.sh关闭Tomcat,有时会关闭成功,有时会出现关闭错误; Jul 06, 2017 10:57:37 AM org.apache.catalina.startup.Cata ...