当前位置: 首页 > 编程日记 > 正文

事务隔离机制原理深入分析以及MySQL不同隔离级别分场景下实验对比

这是我总结的事务的四种隔离机制,比较好理解,主要是有些地方文字游戏说不清楚很容易混淆:

Read Uncommitted(读未提交)A未完,B已更新,未提交,A读到B已更新的数据,由于未提交,那么可能会回滚,所以这样的数据就是错误的数据也就是脏读。

Read Committed(读已提交)A未完,B已更新,已提交,A读到B已更新且提交的数据,由于已提交,所以是正确的数据,但是可能这个事务比较长,读几次都不一样,从业务上说也许对也许不对,所以这个是不可重复读的。

Repeatable Read(可重复读)A未完,B不一定可以更新,不管B有无更新/提交,A读不到B的数据(MYSQL默认),自己每次读都是一样的,但是存在幻读,幻读是期间发送新增删除这样的操作导致。

Serializable(串行化),绝对无错。

-------------

MySQL事务学习总结

关于幻读,网上很多描述都是错误的。

幻读是指读到了其它事务提交的新增数据,

不可重复读是指读到了其他事务提交的更改数据(更改或删除)。

为了解决不可重复读,只需要通过行级锁来实现就可以了,但是为了解决幻读,则不能仅仅锁住一条数据,因为这样的锁不能阻止别的事务新增记录,MySQL用了间隙锁来解决这个问题,而不是表级锁。

InnoDB实现的是MVCCMVCC中,读分为快照读和当前读

MySQL加锁处理分析@何登成的技术博客

快照读(简单的select操作,属于快照读,不加锁)

select * from test where money = 500;

当前读(特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁)

select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;

可能会觉奇怪,为什么insert update delete也属于当前读,因为针对这些操作,都是InnoDB先把数据筛选出来,加锁,把数据交给MySQL Server处理,Server处理好后交给InnoDB更新,然后InnoDB释放锁,这里面就有读的操作。
这里说的幻读指的是当前读。这是登博关于幻读的解释,所谓幻读,就是同一个事务,连续做两次当前读 (例如:select from t1 where id = 10 for update;),那么这两次当前读返回的是完全相同的记录 (记录数量一致,记录本身也一致),第二次的当前读,不会比第一次返回更多的记录 (幻象)。

-----

MySQL数据库间隙锁

当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。

举例来说,假如user表中只有101条记录,其empid的值分别是 1,2,...,100,101,下面的SQL:

select * from  user where user_id > 100 for update;
是一个范围条件的检索,InnoDB不仅会对符合条件的user_id值为101的记录加锁,也会对user_id大于101(这些记录并不存在)的“间隙”加锁。

InnoDB使用间隙锁的目的,一方面是为了防止幻读,以满足相关隔离级别的要求,对于上面的例子,要是不使用间隙锁,如果其他事务插入了user_id大于100的任何记录,那么本事务如果再次执行上述语句,就会发生幻读;另外一方面,是为了满足其恢复和复制的需要
---------------------

下面MySQL书《高性能MySQL(第3版)》:

隔离机制的比较

其实也有人喜欢用锁来控制并发,书中还提到了“隐式”和“显示锁定”,是这么建议的:

虽然这样,但是其实如果不经过实际的演练还是很难理解上面说的事务隔离机制到底怎么样可以防止并发。

1.查看MySQL版本

我们的版本是5.1.7

2.查看存储引擎

>show engines;

存储引擎是:InnoDB

3.实验表

假设有个商品表g,关键字段num表示库存,name表示商品名称

主要就是看不同事务隔离机制下并发修改库存是否会出现超卖。

假设我们的程序需要先查询库存,如果库存>0都可以卖,update扣库存,否则rollback。

为了制造并发肯定需要2个事务,假设是A和B。

4.确认事务隔离机制

修改会话的事务隔离级别

set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;

>select @@global.tx_isolation,@@tx_isolation;

隔离级别1:Serializable 串行化

场景一:

显然一开始AB查询的数据是一样的num=1

A开始update

这时候在等待,无法update。

过一会就超时了。

如果这个时候B也update那么一样会等待超时

所以这样,AB就会都超时。

这时即使commit也是返回0,数据库不会变化。

场景二:

A在update等待的时候,B马上commit,但是B没有update

查看结果

这次A成功的扣库存。

所以从上面可以得出一个结论:serializable是可以很好的控制并发。

然后需要把库存改为1,便于测试。

隔离级别2:read committed 读已提交

>set session transaction isolation level read committed;

>select @@global.tx_isolation,@@tx_isolation;

场景一:

初始化AB查出来的库存都是1,然后A可以update一条数据,无等待。

这时候AB再比较下库存,A已经是0,B是1,因为A没有commit。

然后A执行commit操作,这时候B再查已经是库存0;

这时候B执行update返回是0行,因为update不能满足where条件,所以B只有Commit,然后重新提交。

场景二:

一开始AB都是一样的库存1,然后A开始update,然后A的库存是0,B是1,因为A还没有提交。

这时候B再update

按照前面的经验,B等待其实是再等A提交,A如果一直不提交,B就会超时。

这时A提交commit,B查询就得到A更新后的结果,这时B查到库存是0自然不会去更新,也就只能结束事务。

场景三:

AB先后update,然后A在B超时之前commit,这时由于B已经读到A更新后的结果0,所以B就不能成功update。

隔离级别3.repeatable read 可重复读

>set session transaction isolation level repeatable read;

>select @@global.tx_isolation,@@tx_isolation;

场景一:

然后A开始update,然后A和B分别读到库存是1和0

然后A提交commit,这时候再查看A和B的库存还是保持不变。

这时候B再次尝试update

依然是返回0条,说明更新不成功。

场景二:

AB同时update

如果A不及时commit那么B肯定会超时

如果A及时commit

所以可以看出无论是read committed还是repeatable read只要update的条件where  num>0足够充分都是可以控制并发防止超卖的。

如果没有带where  num>0这个控制条件,那么肯定会可以update成功的。

隔离级别4.read uncommitted

这个是需要杜绝的,就不讨论了。

如果没有带where  num>0,那么会怎么样呢。其实只要理解了上述流程就可以想明白会怎么样。

对于read committed

A已经update,B读到库存是0自然不会去更新;

A没有update,B读到库存是1,这要看A会不会及时提交;

如果A及时提交,B自然会去更新因为满足where条件,且成功,这样就超卖-1;

这时候由于B没有提交,所以AB分别查出0和-1

然后B提交commit,AB查出的都是-1,就不演示了。

修改会话为repeatable read

AB先后update,B在等待

然后A立即提交commit,B马上update得到返回。

结果就是-1产生了超卖:

总结:

1.使用serializable是可以防止超卖,但是性能怎么样需要数据说明;

2.read committed和repeatable read带上where条件库存num>0都是可以防止超卖的,不过需要处理超时。

3.其他各种组合情况还会更复杂,具体具体问题具体分析。

forupdate实验

A开始 :

B开始:

扩展阅读:

《数据库事务的四大特性以及事务的隔离级别》

事务的四个特征ACID

⑴ 原子性(Atomicity)
  原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

⑵ 一致性(Consistency)
  一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

⑶ 隔离性(Isolation)
  隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离

即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

关于事务的隔离性数据库提供了多种隔离级别

⑷ 持久性(Durability)
  持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

------------

事务隔离级别

三种读现象:

⑴ 脏读
  脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
  当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。

⑵不可重复读
  不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
  例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。
  不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据
  在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,

⑶ 幻读
  幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)

MySQL数据库的四种隔离级别:
Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
⑵ Repeatable read (可重复读):可避免脏读、不可重复读的发生。
Read committed (读已提交):可避免脏读的发生。
Read uncommitted (读未提交):最低级别,任何情况都无法保证。

以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。

在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。

相关文章:

cogs 362. [CEOI2004]锯木厂选址

★★★ 输入文件:two.in 输出文件:two.out 简单对比 时间限制:0.1 s 内存限制:32 MB 从山顶上到山底下沿着一条直线种植了n棵老树。当地的政府决定把他们砍下来。为了不浪费任何一棵木…

中小企业低成本快速建站的秘诀——模板建站

从14年至今,小乔已经给很多行业的客户做了不少网站。在跟我咨询建站的这些人当中,其实不乏一些创业初期经济比较紧张的个人/公司。这些个人/公司需要一个网站对外宣传,但又希望可以节省开支,所以他们往往会选择成本低的建站服务&a…

MySQL常用性能分析方法-profile,explain,索引

1.查版本号 无论做什么都要确认版本号,不同的版本号下会有各种差异。 >Select version();2.执行状态分析 显示哪些线程正在运行 >show processlist;下面是完整的信息3.show profile show profile默认的是关闭的,但是会话级别可以开启这个功能&…

MathType在手,公式不求人!

很多论文达人们的论文排版是相当漂亮的,页面也非常整齐美观,即使是理工类的论文,里面有很多的数学符号和公式,排版也是非常整洁,为什么达人们的公式论文能排版的这么完美,而自已却总是不得其门而入&#xf…

Linux系统mongdb还原数据库,linux下mongodb数据库备份与还原

MongoDb数据库备份还原数据库迁移,可视化工具NoSQLBooster for MongoDB 付费版才具有数据导入功能.代价过高,索性采起命令行web数据备份备份命令mongodbmongodump -h dbhost -d dbname -o dbdirectory-h:MongDB所在服务器地址,例如:127.0.0.1…

【逆序对】Ultra - Quicksort

POJ 2299 Ultra-QuickSort 只允许交换,比较相邻的元素, 求最少多少次交换可以使得序列有序 冒泡排序的次数——>数列中逆序对的个数减1——>最终为0 ——>答案为数列中逆序对的个数——> 归并排序求逆序对qwq 注意cnt开long long 不然会炸QA…

Android Touch事件传递机制 二:单纯的(伪生命周期) 这个清楚一点

转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在我想使用一个demo以及一个实例来学习一下Andorid中的Touch事件处理过程。 在Android系统中&#xff0…

SpringBoot使用笔记

其实也是参考官方的:http://spring.io/guides/gs/rest-service/ ,在官方代码基础上加入了很多实用的东西,比如运行环境启动命令等等。 官方文档:http://docs.spring.io/spring-boot/docs/current/reference/html/ SpringBoot并不…

linux卸载欧朋浏览器,如何在Centos下安装opera浏览器

如何在Centos下安装opera浏览器 ,Opera目前是Linux平台上性能最优的浏览器,而且Opera中国团队本身即定位于Opera的研发中心,主要也是负责全球Linux平台项目的开发,这个版本初步解决了经年来Linux上Opera中文字体显示混乱的问题。我…

1-1 分配内存资源给容器和POD

这一小节讲解如何分配内存请求和对一个容器做内存限制。一个容器被保证拥有足够的内存可以处理请求,但是也不允许使用超过限制的内存。 开始之前 需要拥有一个k8s集群 需要安装好一个kubectl 工具,并且能够与集群通信。 如果没有准备好,你…

Java的SPI机制

Dubbo等框架使用到必须掌握。 java.sql.Driver 是 Spi,com.mysql.jdbc.Driver 是 Spi 实现,其它的都是 Api。package org.hadoop.java;public interface IService {public String sayHello(); public String getScheme(); }package org.hadoop.java…

你不知道的对称密钥与非对称密钥

(一)对称加密(Symmetric Cryptography) 对称密钥加密,又称私钥加密,即信息的发送方和接收方用一个密钥去加密和解密数据。它的最大优势是加/解密速度快,适合于对大数据量进行加密,对…

linux sntp 代码,C语言window(linux)平台的SNTP实现

C语言实现window(linux)平台的SNTP,本程序功能主要是实现电脑(或者设备)时间同步。摘录部分代码:unsigned char liVnMode; /* LeapSecond(2bits:0), VersionNumber(3bits: 3), Mode(3bits: Client3, Server4) */unsigned char stratum; /* 时间层级 (0-1…

在typescript中导入第三方类库import报错

问题 最近开始折腾typescript,在使用第三方类库,比如最常见的lodash,采用常规方法导入 import * as _ from lodashvscode中报错提示lodash不是module。 原因 因为第三方类库并没有ts的声明文件,查阅网上资料,有typings…

JavaAgent 实现字节码注入

新建MyAgent项目 pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apach…

php打印中文乱码

php文档的文本格式都设置成 utf-8 格式 在代码中添加 header("content-type:text/html; charsetutf-8"); 转载于:https://www.cnblogs.com/negro-guoguo/p/5421355.html

linux孤立cpu,Linux 抛弃旧款 CPU,一下子少 50 万行代码

IT 之家4 月 3 日消息 Linux 内核维护者已经决定在即将发布的新版本中抛弃对旧款 CPU 架构的支持&#xff0c;因此 Linux 4.17 内核将减少大约 500000 行代码&#xff0c;根据 Linux 统计器&#xff0c;目前它包含大约 2030 万行代码。IT 之家报道&#xff0c;将被弃用的体系架…

CSS3 从头捋

1.border-radius 边界半径 作用&#xff1a;该属性用来实现圆角 示例1实现圆角 div {border:2px solid red;width:300px;border-radius:25px; } 示例2实现圆 div {border: 1px solid red;height: 100px;width: 100px;border-radius: 50%; } 示例3 不规则圆 div {border: 1px s…

算法:详解布隆过滤器的原理、使用场景和注意事项@知乎.Young Chen

算法&#xff1a;详解布隆过滤器的原理、使用场景和注意事项知乎.Young Chen 什么是布隆过滤器 本质上布隆过滤器是一种数据结构&#xff0c;比较巧妙的概率型数据结构&#xff08;probabilistic data structure&#xff09;&#xff0c;特点是高效地插入和查询&#xff0c;可…

linux shell显示下载进度,shell脚本测试下载速度

在linux下用shell来测试下载速度&#xff0c;很实用的shell代码。代码&#xff1a;复制代码 代码示例:#!/bin/bash#date:20140210# edit: www.jquerycn.cn#used for test server download speedr_host"188.18.28.19"r_dir"/home/test0208/tmp"r_file"…

openStack调试

openStack调试 posted on 2016-04-23 22:07 秦瑞It行程实录 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/ruiy/p/5425823.html

快应用开发常见问题以及解决方案【持续更新】

接触快应用也有一段时间了&#xff0c;踩过了大大小小的坑&#xff0c;让我活到了今天。准备在此立贴持续更新&#xff0c;记录遇到的问题以及解决方案&#xff0c;造福大众。css 方面 1、文字竖排不支持 目前官方还不支持writing-mode&#xff0c;除了等待官方支持这个api以外…

Java字节码研究

关于怎么查看字节码的五种方法参考本人另一篇文章《Java以及IDEA下查看字节码的五种方法》 1.String和常连池 先上代码&#xff1a; public class TestApp {public static void main(String[] args) {String s1 "abc";String s2 new String("abc");St…

在c语言中逗号的作用,关于c语言中的逗号运算符???

等下。。答错了。。还需要理解一下神马是逗号表达式。。我前面说的和uuyyhhjj与delta_charlie的意思一样&#xff0c;但其实我们都搞错了。你可以自己把我们的例子都运行一下&#xff0c;看看是不是这样。下面我感觉应该是我正确的理解。逗号表达式是所有运算符中优先级最低的&…

2018-2019-1 20165206 《信息安全系统设计基础》第4周学习总结

- 2018-2019-1 20165206 《信息安全系统设计基础》第4周学习总结 - 教材学习内容总结 程序员可见的状态&#xff1a;Y86-64程序中的每条指令都会读取或修改处理器状态的某些部分&#xff0c;这称为程序员可见状态。包括&#xff1a;程序寄存器、条件码、程序状态、程序计数器和…

PHP——图片上传

图片上传 Index.php文件代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Document</title> </head> <body><form action"upload2.php" method"p…

IDEA实用插件和技巧

《解决lambda expressions are not supported at this language level的问题》 《Intellij Idea 代码格式化/保存时自动格式化》 一、安装google-java-format preferences -> plugins -> Browse repositories… 搜索google-java-format 还有阿里的代码规范插件也不…

c语言将字母与数字分开存放,2017年计算机二级《C语言》考前提分试题及答案9...

二、程序填空题(共18分)、下列给定程序中&#xff0c;函数flm的功能是&#xff1a;将s所指字符串中的所有数字字符移到所有非数字字符之后&#xff0c;并保持数字字符串和非数字字符串原有的次序。例如&#xff0c;s所指的字符串为“def35adh3kjsdt7”&#xff0c;执行后结果为…

学术青年如何克服拖延症——5条技巧助你前进

雷锋网 AI 科技评论按&#xff1a;「我准备好了就开始」&#xff08;或者说「拖延症」&#xff09;&#xff0c;以及「即便动起手来也觉得举步维艰」大概是每个现代人都逃不过的日常感受&#xff0c;不管是学习、在企业中工作&#xff0c;还是从事学术研究。我们可能都看过许多…