深入理解mysql锁与事务隔离级别

一、锁

1、锁的定义

锁即是一种用来协调多线程或进程并发使用同一共享资源的机制

2、锁的分类

  • 从性能上分类:乐观锁和悲观锁
  • 从数据库操作类型上分类:读锁和写锁
  • 从操作粒度上分类:表锁和行锁

2.1 从性能上分类

2.1.1 乐观锁

乐观锁顾名思义就是操作的时候很乐观,认为操作不会产生并发问题(不会有其他线程对数据进行修改),因此不会上锁。但是会在更新时判断其他线程再这之前有没有对数据进行修改,一般会使用版本号机制或CAS算法实现。

2.1.1.1 版本号机制

实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时,set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

version可以自定义,也可以使用时间戳来作为版本编号

示例SQL:

update table set name = ‘anna‘,version = version+1 where id = #{id} and version = #{version}
2.1.1.2 CAS算法

乐观锁的另一种技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新表变量的值,而其他线程都失败,失败的线程并不会呗挂起,而是被告知在这次竞争中失败,并可以再次尝试。

CAS操作中包含三个操作数:

  • 需要读写的内存位置V
  • 进行比较的预期原值A
  • 拟写入的新值B

如果内存位置V的值与预期原值A匹配,则将B写入内存位置V中替代A,如果预期原值A不匹配则不做任何操作。无论那种情况,他都会在CAS指令之前返回该位置的值(在CAS的一些特殊情况下仅返回CAS是否成功,而不提取当前值)。这其实和乐观锁的冲突检查+数据更新的原理时一致的。

2.1.2 悲观锁

总是假设最坏的情况,每次取数据都会认为其他线程会修改,所以都会加锁。一旦加锁,不同线程同时执行的时,只能有一个线程执行,其他线程在入口出等待,知道锁被释放。

悲观锁在Mysql和JAVA中被广泛应用

  • MYSQL的读锁、写锁、行锁等
  • Java的synchronized关键字

使用建议:

读得多,冲突几率小,使用乐观锁

写的锁,冲突几率大,使用悲观锁


2.2 从数据库操作类型上分类

2.2.1 读锁

读锁在加锁时允许其他事务进行查询操作,但不允许进行修改操作,即共享锁。

2.2.2 写锁

写锁在加锁时则不允许其他事务进行任何操作,即排他锁。

2.3 从操作粒度上分类

2.3.1 表锁

顾名思义,会将整个表加锁,这种方式加锁粒度大,加锁块、开销小,不会产生死锁。但是并发执行情况下效率较低、容易发生锁冲突。

2.3.2 行锁

行锁会对被操作的数据行进行加锁,这种方式加锁粒度小、加锁慢、开销大,可能会产生死锁。但是并发执行情况下效率高,不容易发生锁冲突。

innodb中的行锁时针对索引加锁而非针对记录。如果索引失效,就会从行锁升级为表锁。


在Mysql中MyISAM的引擎仅支持表锁,每次进行查询操作都会对表加读锁,进行修改操作则加写锁。MyISAM并不支持事务和行锁,而innodb支持行级锁和事务,这也是MyISAM和Innodb最大的不同。


二、事务

1、事务的定义

事务时由一组SQL语句组成的逻辑处理单元。

2、事务的特性

事务具有四种特性:原子性、一致性、隔离性、持久性。

  • 原子性:事务中所有操作应具有原子性,即要么都执行要么都不执行
  • 一致性:指操作执行前后的数据具备一致性。这意味着,所有相关的数据规则都必须应用于事务的修改,以保证数据的完整性。事务结束时,所有的数据结构也都必须是正确的。
  • 隔离性:每个事务都有其独立的环境,事务的的中间状态不为外界可见,反之亦然。
  • 持久性:当事务提交之后,它对数据库数据的改变具有持久性,即便数据库宕机重启后数据库的数据状态应该依然是事务提交之后的结果。

3、并发事务处理带来的问题

  • 更新丢失:当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生更新丢失的问题-最后的更新覆盖的有其他事务所做的更新。
  • 脏读:事务读取到了其他事务修改但未提交的的值,而之后那个事务进行了回滚,那么当前事务所读取到的数据就是脏数据,不符合事务的一致性。
  • 不可重复读:当前事务在一开始读取了一行数据,而在那之后另一个事务提交了一个对于该行的更新,那么当此事务再次去读取同一行数据时,读取到的结果和第一次的不同、或则这一条记录已被删除,这种现象就叫做不可重复读。
    也就是说事务读取到了其他事务已提交的数据,不符合隔离性。
  • 幻读:事务A读取到了事务B已提交的新增的数据,不符合隔离性

4、事务的隔离级别

为了解决并发事务处理所带来的问题,mysql提供了4种事务隔离级别以供我们选择。

  • 读未提交(read uncommit):可以读取到事务未提交的修改
  • 读已提交(read commit):可以读取到事务已提交的修改
  • 可重复读(repeatable read):事务进行中不会读取到其他事务已提交的修改,只会使用第一次查询时所获得的快照结果。这里使用到了MVCC(多版本并发控制)机制来达到这个效果。
  • 串行化(Serializable):将事务转化为串行的形式来执行,该级别会进行锁表,因此不会出现幻读的情况,这种隔离界别的并发性极低,开发种很少会用到。

数据库的事务隔离级别越严格,那么并发所带来的副作用就越小,但是并发执行的效率也就越低,因为事务隔离级别就是在一定程度上使事务“串行化”进行,这显然与“并发”相矛盾。

所以应该合理的去选择事务隔离级别,根据业务场景对于数据的敏感程度进行选择。

间隙锁:使用间隙锁可以在可重复读的隔离级别下避免幻读,使用下面SQL语句
update account set name = ‘tufeu‘ where id>=5  and id < 7;
在事务开头执行这一语句,可以使得其他事务无法在当前事务未提交前在id为5到7之间插入数据,这就是间隙锁
当然如果你不想真的修改数据的话,请保证间隙锁范围内没有数据。

在seesion_1种使用间隙锁

在session_2种插入新数据因为id自增所以新id为6,在间隙锁范围内,被阻塞导致超时,插入失败。

不过由于大部分场景下不需要处理幻读的情况,所以平时要尽量避免间隙读,因为这样的确会降低并发效率

MVCC机制:

mvcc机制底层由undo log实现,这里以一种较为简单的方式说明机制

首先要明确每个事务都有一个自己的id,事务的id只有在事务执行第一条sql语句时才会分配,mysql的事务id分配严格按照事务的创建顺序来进行。

我们可以看作每一条数据都有两个隐藏的字段创建事务id和删除事务id(可为空)

当我们修改一条数据的时候,不会直接修改,而是新增一条修改过后的数据id和原数据一致(这里是假设不是真实实现,不考虑id重复这个问题)

当我们删除的时候,会将当前做删除操作的事务id记录再”删除事务id“列上

当我们查询一条记录是,会创建一个查询快照,记录此刻的最大已提交事务id。

当我们再次查询的时候会在mysql底层带上过滤条件,创建事务id<=max(当前事务id,快照点已提交最大事务id) and 删除事务id>max(当前事务id,快照点已提交最大事务id)

查询结果不一定唯一,以创建事务id最大的那个为准。

id name balacne create_id del_id
1  a	100	11
2  b	200	12    12
3  c 	300	12
1  a	120	14

比如上面这几行数据,假如我们事务id为11 和 12 新增前三条数据,然后新开一个事务id为13的事务,进行查询操作select * form account,的到一个快照,并获得当前的最大已提交事务id为12,不去提交13,新创建一个事务id14,修改id为1的语句,这个时候,mysql会新增一条数据为修改过后的样子,有其事务创建id为14,这个时候我们用事务13去查询,查询语句回事 select * from account where 创建事务id<=max(当前事务id(13),快照点最大提交id(12)) and 删除事务id>max(当前事务id(13),快照点最大提交id(12)),如果没有删除事务id则忽略这个条件,这个时候应该可以看出我们查询出来的数据只会是第一条,因为第四条的创建事务id为14。

我们再看id为2的数据,根据上面的sql查询语句,我们可以看出他的删除事务id为12小于max(当前事务id,快照点最大提交id)所以无法查询到该数据。

优化建议:
  • 尽可能的让数据检索通过索引完成,避免无索引行锁升级为表锁
  • 合理设计索引,尽量缩小锁的范围
  • 极可能减少检索条件范围,避免间隙锁
  • 尽量控制事务大小,减少锁定资源量和时间长度,设计事务加锁的sql尽量放在事务最后执行
  • 尽可能使用低级别的事务隔离以提升并发效率

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

来自为知笔记(Wiz)

原文地址:https://www.cnblogs.com/qishanmozi/p/e972c92103cf3735872d88657a013df9.html

时间: 2024-09-30 11:29:51

深入理解mysql锁与事务隔离级别的相关文章

面试必问的MySQL锁与事务隔离级别

之前多篇文章从mysql的底层结构分析.sql语句的分析器以及sql从优化底层分析, 还有工作中常用的sql优化小知识点.面试各大互联网公司必问的mysql锁和事务隔离级别,这篇文章给你打神助攻,一飞冲天. 锁定义 锁是计算机协调多个进程或线程并发访问某一资源的机制. 在数据库中,除了传统的计算资源(如 CPU.RAM.I/O等)的争用以外,数据也是一种需要用户共享的资源.如何保证数据并发访问的一致性.有效性是所有数据库需要解决的问题,锁冲突也是影响数据库并发性能的一个重要因素. 锁分类 从性能

第36讲 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景

在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种数据库自身体系结构的理解.今天这一讲,作为补充 Java 面试考察知识点的完整性,关于数据库的应用和细节还需要在实践中深入学习.今天我要问你的问题是,谈谈 MySQL 支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景?典型回答所谓隔离级别(Isolation Level),就是在数据库事务中,

浅谈mysql中不同事务隔离级别下数据的显示效果

事务的概念 事 务是一组原子性的SQL查询语句,也可以被看做一个工作单元.如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查 询语句因为崩溃或其他原因而无法执行,那么所有的语句就都不会执行.也就是说,事务内的语句要么全部执行,要么一句也不执行. 事务的特性:acid,也称为事务的四个测试(原子性,一致性,隔离性,持久性) automicity:原子性,事务所引起的数据库操作,要么都完成,要么都不执行consisitency:一致性,事务执行前的总和和事务执行后

mysql中不同事务隔离级别下数据的显示效果--转载

事务是一组原子性的SQL查询语句,也可以被看做一个工作单元.如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查询语句因为崩溃或其他原因而无法执行,那么所有的语句就都不会执行.也就是说,事务内的语句要么全部执行,要么一句也不执行. 事务的特性:acid,也称为事务的四个测试(原子性,一致性,隔离性,持久性) automicity:原子性,事务所引起的数据库操作,要么都完成,要么都不执行 consisitency:一致性,事务执行前的总和和事务执行后的总和是不变的

[转帖]深入理解 MySQL—锁、事务与并发控制

深入理解 MySQL—锁.事务与并发控制 http://www.itpub.net/2019/04/28/1723/ 跟oracle也类似 其实所有的数据库都有相同的机制.. 学习了机制才能够更好的工作,. 数据和云 2019-04-28 10:45:07 本文共11796个字,预计阅读需要30分钟. 本文对 MySQL 数据库中有关锁.事务及并发控制的知识及其原理做了系统化的介绍和总结,希望帮助读者能更加深刻地理解 MySQL 中的锁和事务,从而在业务系统开发过程中可以更好地优化与数据库的交互

[转帖]2019-03-26 发布 深入理解 MySQL ——锁、事务与并发控制

深入理解 MySQL ——锁.事务与并发控制 https://segmentfault.com/a/1190000018658828 太长了 没看完.. 数据库 并发  mysql 639 次阅读  ·  读完需要 46 分钟 21 本文首发于 vivo 互联网技术微信公众号 https://mp.weixin.qq.com/s/JF...作者:张硕 本文对 MySQL 数据库中有关锁.事务及并发控制的知识及其原理做了系统化的介绍和总结,希望帮助读者能更加深刻地理解 MySQL 中的锁和事务,从

mysql 4中事务隔离级别

SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的.低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销.Read Uncommitted(读取未提交内容) 在该隔离级别,所有事务都可以看到其他未提交事务的执行结果.本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少.读取未提交的数据,也被称之为脏读(Dirty Read).Read Committed(读取提交内容) 这是大多数数据库系统的默认隔离级别(但不是MySQL默认的).

30秒读懂mysql四种事务隔离级别

一.事务的基本要素(ACID) 1.原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节.事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样.也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位.  2.一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 .比如A向B转账,不可能A扣了钱,B却没收到. 3.隔离性(Isolation):同一时间,只允许一个事务请求同一数据,

(转)SQL SERVER的锁机制(三)——概述(锁与事务隔离级别)

五.锁与事务隔离级别 事务隔离级别简单的说,就是当激活事务时,控制事务内因SQL语句产生的锁定需要保留多入,影响范围多大,以防止多人访问时,在事务内发生数据查询的错误.设置事务隔离级别将影响整条连接. SQL Server 数据库引擎支持所有这些隔离级别: · 未提交读(隔离事务的最低级别,只能保证不读取物理上损坏的数据) · 已提交读(数据库引擎的默认级别) · 可重复读 · 可序列化(隔离事务的最高级别,事务之间完全隔离) SQL Server 还支持使用行版本控制的两个事务隔离级别.一个是