一、事务

数组库的一组操作,要么全部成功,要么全部失败

举例:银行转账 A账户向B账户转100

A账户余额扣去100

B账户余额增加100

上述两个操作要么全部成功,要么全部失败,部分成功或失败,数据就错乱了

1. 事务的四大特征

原子性:事务是原子性操作,要么全部成功,要么全部失败

一致性:多个事务对数据库操作会保证数据一致性

隔离性:并发时,事务之间互不影响

持久性:事务提交之后对数据库的影响是持久性的,不会因为数据库宕机导致数据丢失

2. 并发事务带来的问题

脏读

在一个事务中,读取了其他事务未提交的数据

不可重复读

在一个事务中,同一行记录被访问了两次却得到了不同的结果

幻读

在一个事务中,同一个范围内的记录被读取时,其他事务向这个范围添加了新的记录。

前面脏读和不可重复读容易理解,幻读稍微难一点

假设图一test开始是空表,事物1第一次查询得到空表,事物2在事物1执行期间插入一条数据,

事物1第二次查询由于满足可重复读,所以查询结果依然为空,但是事物1插入同样一条数据,报重复主键错误

幻读两个要素:

可重复读隔离级别下,快照读看到的是一致性视图,只有当前读才会产生幻读

幻读专指新插入发行,更新不算,将上述查询后面加上For Update,就会将事务2插入的数据读出来,这就是幻读

3. 事务隔离级别

为了解决上述并发事务问题,MySQL数据库提供了事务隔离级别

事物隔离级别

脏读

不可重复读

幻读

读未提交(read-uncommitted)

读已提交(read-committed)

可重复读(repeatable-read)

串行化(serializable)

可重复读是MySQL默认级别

二、重要概念

1. MVCC和事务隔离的实现

同一数据库记录可以在系统中存在多个版本,这就是MVCC (多版本并发控制)

不同时刻开启的事务会创建不同的视图,后续直接从视图读取数据,达到数据隔离,当然数据隔离还需要数据库锁的帮助

InnoDB 里面每个事务有一个唯一的事务 ID,叫作 transaction id,在事务开始的时

候向 InnoDB 的事务系统申请的,是按申请顺序严格递增

在MySQL中,每条记录的更新都会记录一条undo Log,记录上最新的值通过回滚可以,都可以得到前一个状态的值

上图中,数据库一行记录有多个版本,每个版本有自己的 row trx_id,最新版本V4的k=22,是被row trx_id=25事务更新的,不同时刻启动的事务看到不同的视图,而V1,V2,V3不是物理上真实存在的,要想得到它们需要根据当前版本和undo Log(回滚日志)计算,比如V1的值需要执行U3,U2,U1才能得到

undo Log日志如果一直存在,可能会严重占据磁盘空间,当系统没有比undo Log更早的视图时,就会把undo Log删除掉

长事务一般会保存很老的事务视图,导致其它事务的undo Log无法删除,所以在这个事务提交前,可能会导致大量undo Log存在,我们需要避免使用长事务

2. 视图

用查询语句定义的虚拟表,在调用的时候执行查询语句并生成结果。这是我们常说的视图

InnoDB 用来实现 MVCC 时用到的一致性读视图,即 consistent read view, 用于支持 RC(Read Committed,读提交)和 RR(Repeatable Read,可重复读)隔离级别的实现。没有物理结构,仅仅是逻辑上用来定义在事务执行期间能看到什么数据

3. 事务的起点

begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作 InnoDB 表的语句,事务才真正启动, start transaction with consistent snapshot 该命令可以立即启动事务

4. 隔离级别与视图的关系

“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念

“读提交”隔离级别,这个视图是在每个 SQL 语句开始执行的时候创建的

“可重复读”隔离级别: 视图是在事务启动 (执行第一条语句或者使用特定命令) 时创建的,整个事务存在期间都用同一个视图

“串行化”隔离级别下直接用加锁的方式来避免并行访问

5. 当前读与快照读

当前读,在事务执行过程中可以读到其它已已提交事务的最新数据

快照读,在事务执行过程中只能看到从事务起点创建的一致性视图,并不能读到其它已提交数据

在RR(可重复读)级别下,快照读满足以下两个规则:

读取的记录:更新的事务ID <= 当前事务ID

读取的记录:删除的事务ID > 当前事务ID(小于的话数据都删了,肯定读不到)

三、MySQL锁分类

按照不同维度可分为:

1)

悲观锁

乐观锁

2)

共享锁(写锁)

排它锁(读锁)

3)

意向共享锁

意向互斥锁

意向锁其实不会阻塞全表扫描之外的任何请求

假设没有意向锁,两个请求,一个修改数据某一行记录,另一个需要修改该表所有行记录,这时需要就需要对所有的行是否被锁定进行扫描,引入意向锁,只需要判断该表有没有意向锁,等待修改单行事务提交,意向锁释放

4)

全局锁

表锁和元数据锁(meta data lock 简称(MDL))

行锁

全局锁:对整个数据库实例加锁

作用: MyISAM不支持事务拿不到一致性视图,需要加全局读锁做逻辑备份。加读锁期间数据库只能读,不能写。

表锁:使用lock tables 命令来锁住整个表,一般不使用

MDL: 当对表做增删改查操作时,需要加MDL读锁;当需要对表做结构变更操作时需要加MDL写锁(见其它篇文章)

所以如果有两个线程,一个对表做读操操作,一个需要给表加字段,第二个操作会被阻塞。

在给表加字段的时候,如果该表请求频繁,这时会无法获取MDL写锁,同时会阻塞后续业务请求拿读锁。

解决方法:在 alter table语句里面设定等待时间,如果在指定的等待时间里面能够拿到 MDL 写锁最好,拿不到也不要阻塞后面的业务语句,先放弃。

行锁: 在引擎层实现,MyISAM不支持行锁。

重要概念: 两阶段加锁

在数据库更新时会给扫描的数据行加行锁,更新结束不会立马释放行锁,需要等到事务提交才会释放行锁。

由于两阶段锁的存在,所以在一个事务中,更新语句如果放在前面,会阻塞其它事务对表的更新,影响并发。对于更新频繁的语句尽量放在事务的靠后部分

死锁

解决方案:

超时等待

发起死锁检测,主动回滚其中某个事务

超时等待的时间根据业务执行时间制定,太短误伤,太长会影响并发量

死锁检测有额外负担,在事务被锁住,需要查看其依赖的线程是否被锁住,一直循环,最后判断出现死锁,在多个线程并发修改同一行数据时,时间复杂度会变成O(n^2),会导致CPU利用率很高,却执行不了几个事务。一般通过控制并发来解决

5)

记录锁(record Lock)

间隙锁(Gap lock)

next-key

在另一篇文章中详细讲解了加锁情况

数据库的行锁实际上record Lock,会对扫描的行加锁,如果没有走索引,扫描全表,会锁住整个表的所有行。

例:

CREATE TABLE `t` (

`id` int(11) NOT NULL,

`c` int(11) DEFAULT NULL,

`d` int(11) DEFAULT NULL,

PRIMARY KEY (`id`),

KEY `c` (`c`)

) ENGINE=InnoDB;

语句1:select * from t where id >3 for update;

语句2:select * from t where d > 3 for update;

语句1会走主键索引,对扫描到的行数加锁

语句2不走索引,扫描全表,对所有行加record lock

在可重复读的隔离级别下:

每次开启事务,会生成一致性视图,看不到其它事务已经提交的修改,在前面已经提过

更新语句先读后写,这个读是当前读,就算我们对所有数据加上record lock,也不能阻止数据的插入。这样我们在当前读中还是会读到插入的数据,形成幻读。

如何避免幻读?

使用Gap lock + record lock

间隙锁是对索引记录中的一段连续区域的锁

SELECT * FROM users WHERE id BETWEEN 10 AND 20 FOR UPDATE;

这个语句阻止其他事务向表中插入 id = 15 的记录,因为整个范围都被间隙锁锁定

虽然间隙锁中也分为共享锁和互斥锁,不过它们之间并不是互斥的,也就是不同的事务可以同时持有一段相同范围的共享锁和互斥锁,它唯一阻止的就是其他事务向这个范围中添加新的记录

间隙锁的引入,可能会导致同样的语句锁住更大的范围,但是它只在可重复读级别下才会生效

Next-Key是记录锁和记录前的间隙锁的结合,每个 next-key lock 是前开后闭区间

select * from t where id = 5

会加上(4, 5]的next-key,同时会加上(5, 6]的间隙锁

next-key的加锁原则是锁定的是当前值和前面的范围

注:一般生产都会设置读已提交级别,这个时候为了防止binlog和数据库数据不一致需要设置binlog格式为row,在代码中使用锁来解决并发问题。数据库应该尽可能简单,不管是语句,还是隔离级别,保证数据库的性能。

参考

丁奇老师 MySQL45讲

mysql如何实现读提交锁_MySQL学习笔记(二)—MySQL事务及锁详解相关推荐

  1. 【相机标定与三维重建原理及实现】学习笔记1——相机模型数学推导详解

    目录 前言 一.小孔成像模型 二.坐标系的变换 1.世界坐标系到相机坐标系的变换(刚体变换)[xw^→xc^\boldsymbol {\hat{x_{w}}}\rightarrow \boldsymb ...

  2. mysql新增表字段回滚_MySql学习笔记四

    MySql学习笔记四 5.3.数据类型 数值型 整型 小数 定点数 浮点数 字符型 较短的文本:char, varchar 较长的文本:text, blob(较长的二进制数据) 日期型 原则:所选择类 ...

  3. mysql innodb 事务_MySQL学习笔记之InnoDB事务实现

    我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式. 同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力. 所以 ...

  4. mysql里面有没有map类型_MySQL学习(二) 数据类型

    MySQL支持多种列类型:数值类型.日期/时间类型和字符串(字符)类型. 数值类型 数值类型又分为整数型与小数型 整数型 下面的表显示了需要的每个整数类型的存储和范围 创建一张表 mysql> ...

  5. 查看mysql的启动日志目录下_mysql诊断启动问题、查看日志文件详解

    诊断启动问题 服务器启动问题通常在对MySQL配置或服务器本身进行更改时出现.MySQL在这个问题发生时报告错误,但由于多数MySQL服务器是作为系统进程或服务自动启动的,这些消息可能看不到. 在排除 ...

  6. mysql去重函数的使用方法_MySQL中使用去重distinct方法的示例详解

    一 distinct 含义:distinct用来查询不重复记录的条数,即distinct来返回不重复字段的条数(count(distinct id)),其原因是distinct只能返回他的目标字段,而 ...

  7. mysql启动失败 查看日志文件_mysql诊断启动问题、查看日志文件详解

    诊断启动问题 服务器启动问题通常在对MySQL配置或服务器本身进行更改时出现.MySQL在这个问题发生时报告错误,但由于多数MySQL服务器是作为系统进程或服务自动启动的,这些消息可能看不到. 在排除 ...

  8. SNMP学习笔记之SNMP 原理与实战详解

    原文地址:http://freeloda.blog.51cto.com/2033581/1306743 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法 ...

  9. RT-Thread学习笔记|TCS34725 RGB 颜色识别传感器详解

    rt-thread是什么? RT-Thread 是一个集实时操作系统(RTOS)内核.中间件组件和开发者社区于一体的技术平台,组件完整丰富.高度可伸缩.简易开发.超低功耗.高安全性的物联网操作系统.R ...

最新文章

  1. 全球及中国无菌粉末注射用橡胶塞行业运营模式分析及产销需求预测报告2021年版
  2. 租不起房!你离逃离北上广还有多长时间?
  3. 二叉树学习之非递归遍历
  4. [转]工程师进阶之路(三)
  5. 拓端tecdat:R语言主成分回归(PCR)、 多元线性回归特征降维分析光谱数据和汽车油耗、性能数据
  6. 新概念英语2电子版_新概念英语读100遍,英语能超神
  7. C/C++[codeup 1978]排序
  8. 侠客行java_侠客行
  9. Android studio创建Java测试类
  10. 关于复数i本质的探讨
  11. 用J-Link调试S3C6410(2) --- 运行Leds程序:jink原理
  12. 如何快速入侵一个网站
  13. IDEA惊天bug:进程已结束,退出代码-1073741819 (0xC0000005)
  14. NLP 自然语言处理实战
  15. LightGBM 原理、代码最全解读!
  16. 快手引流卖什么暴利?很多人现在都觉得在各大平台引流很难
  17. 离散数学期末基础知识点复习
  18. 单工,半双工,全双工通讯
  19. Selenium+Python3爬取微博我发出的评论信息
  20. java第七封印游戏_《第七封印》游戏攻略

热门文章

  1. 偏最小二乘法回归(Partial Least Squares Regression)
  2. 新手入门深度学习 | 1-2:编译器Jupyter Notebook
  3. numpy.random.randint详解
  4. NP-Hard问题及组合最优化问题
  5. 支付系统的对账处理与设计--转
  6. 当我们在谈深度学习时,到底在谈论什么(一)--转
  7. Jenkins配置基于角色的项目权限管理--转
  8. 研磨设计模式之 策略模式--转
  9. 你知道你的程序到底能使用多少内存吗?
  10. Apache ZooKeeper - 集群中 Leader 的作用_事务的请求处理与调度分析