前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >mysql 锁机制与四种隔离级别

mysql 锁机制与四种隔离级别

作者头像
用户3147702
发布2022-06-27 12:29:46
6910
发布2022-06-27 12:29:46
举报
文章被收录于专栏:小脑斧科技博客

1. 概述

工作中使用 mysql 比较多,mysql 之所以在业内具有如此崇高的地位,与他严密的加解锁逻辑也是分不开的。 本文进行了一番总结。

2. 两阶段锁协议

Innodb 使用的是两阶段锁协议,指的是将整个事务分成两个阶段,前一个阶段为加锁阶段,后一个阶段为解锁阶段。 在加锁阶段,事务只能加锁和操作数据,不能解锁。 一旦事务释放了一个锁,那么事务就进入解锁阶段,在解锁阶段,除了操作数据外,只能解锁,不能加锁。 两阶段锁协议使得事务有较高的并发度,但是并没有解决死锁问题,如果两个事务分别申请了 A、B 两把锁,接着有申请对方的锁,就会进入死锁状态。 Innodb 只有在 commit 或 rollback 时才会同时释放所有的锁。

3. 显式锁 — select … lock in share mode & for update

Innodb 除了上文所说的隐式锁,还支持在 select 语句中显式锁定某行:

  • select … lock in share mode;
  • select … for update;

LOCK IN SHARE MODE 锁定当前查询的行,不允许其他事务对行进行写操作,但其他事务可以进行读操作。 FOR UPDATE 锁定行,阻止其他事物对该行的任何读写操作。

4. MVCC

mysql 的事务性存储引擎大多使用一种用来增加并发性的加锁机制 — 多版本并发控制(MVCC),在 Oracle、PostgreSQL 及其他一些数据库系统中同样使用该机制实现锁机制,所以也称为乐观锁。 MVCC 在许多情况下避免了使用锁,同时可以提供更小的开销,根据实现的不同,他可以允许非阻塞式读。 MVCC 会保存某个时间点上的数据快照,以保证无论事务需要跑多久,他都将看到一个一致的数据视图,而这也意味着,不同的事务在相同的时间可能看到同一个表的数据是不同的。 并发控制分为乐观的并发控制和悲观的并发控制,每个存储引擎的实现不同。

InnoDB 通过为每一行记录添加两个额外的隐藏值来实现 MVCC,这两个值一个记录这行数据何时被创建时的系统版本号,一个记录这行数据何时被删除时的系统版本号,每个事务在开始的时候都会记录他自己的系统版本号,每个查询必须去检查每行数据的版本号与事务的版本号是否相同。 只有事务版本号小于等于记录的删除版本号并且大于等于记录的创建版本号的记录才会被事务查询到。

这样,对数据库行的增加、删除和更新根本不需要加锁。

  • 插入数据 — 为这个新行记录当前的系统版本号
  • 删除数据 — 将当前系统版本号写入这一行的删除版本号
  • 更新数据 — 创建一个数据的新拷贝,并将新行的创建系统版本号和旧行的删除版本号都设置为当前版本号

只有在 commit 的时候才会发生真正意义的删除。

5. 快照读和当前读

1. 快照读 — 简单的 select 操作,不加锁 2. 当前读 — 特殊的读操作,如插入、更新、删除等操作,属于当前读,需要加锁

6. MySQL 的隔离级别

InnoDB 定义了以下四种隔离级别: 1. Read Uncommitted(读取未提交内容) — 在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read) 2. Read Committed(读取提交内容) — 这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果,同时,也存在幻读的问题 3. Repeatable Read(可重读) — 这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题 4. Serializable(可串行化) — 这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争,所以不建议使用

7. 事务隔离可能引起的问题

上述的四种隔离级别可能引起下面的问题: 1. 脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的 2. 不可重复读(Non-repeatable read) — 在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。 3. 幻读(Phantom Read) — 在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的

四种隔离级别可能引起的问题

隔离级别

脏读

不可重复读

幻读

读未提交(Read Uncommitted)

Y

Y

Y

读已提交(Read Committed)

X

Y

Y

可重复读(Repeatable Read)

X

X

X

可串行化(Serializable)

X

X

X

8. mysql 修改事务隔离级别

用户可以用SET TRANSACTION语句改变单个会话或者所有新进连接的隔离级别。

代码语言:javascript
复制
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL
    {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

默认的行为(不带session和global)是为下一个(未开始)事务设置隔离级别。 如果你使用GLOBAL关键字,语句在全局对从那点开始创建的所有新连接(除了不存在的连接)设置默认事务级别,需要SUPER权限。 使用SESSION 关键字为将来在当前连接上执行的事务设置默认事务级别。

任何客户端都能自由改变会话隔离级别(甚至在事务的中间),或者为下一个事务设置隔离级别。

9. 查询全局和会话事务隔离级别

可以用下列语句查询全局和会话事务隔离级别:

代码语言:javascript
复制
SELECT @@global.tx_isolation; 
SELECT @@session.tx_isolation; 
SELECT @@tx_isolation;

10. 实例

10.1. mysql 默认事务隔离等级

由图可见,mysql 默认是使用 RR 的隔离方式执行的。

我们创建了一个表用于测试,并插入了5条测试数据:

10.2. Read Uncommitted

首先我们将当前 session 的隔离级别设置为 READ UNCOMMITTED,并开启一个新的事务,然后执行一次查询,可以看到查询到了原始的数据。

这时,我们打开一个新的终端,同样开启一个新的事务,并执行一条 update 语句更新数据。

接下来,我们切换到原来的终端,重新执行查询:

我们发现数据发生了变化,然而执行 update 语句的终端并没有提交事务,我们看到出现了脏堵现象。

10.3. Read Committed

与上面一样,我们首先将当前 session 的隔离级别设置为 READ COMMITTED,然后开启一个新事务,并执行一次查询,可以看到查询到了原始数据。

然后,在另一个终端中,我们同样开启一个新事务并执行一条 update 语句更新数据。

在更新事务尚未提交时,我们回到开始的终端,重新执行查询。

可以看到,脏读问题已经不存在了。

那么,接下来,我们在提交另一个终端中的更新事务,并回到开始的终端中重新执行查询:

我们看到,开始的终端里查询到的数据发生了变化,出现了不可重复读的问题。

同时我们在另一终端中开启新的事务,插入一条数据并提交事务,然后我们再在原来的终端中查询数据。

我们看到,原来的终端的查询结果看到了新增的数据,出现了幻读问题。

10.4. Repeatable Read

同样的,我们切换到 REPEATABLE READ 隔离方式,然后查询原始数据:

此时,我们在另一个终端中执行插入并提交:

然后回到开始的终端查询:

可以看到,幻读的问题已经被解决了。

10.5. Serializable

串行化的隔离方式会明显降低事务的处理效率,因此不建议使用,由于他保证事务的严格传行执行,所以可以保证上述问题的避免,这里我们不做实践了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-06-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小脑斧科技博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 概述
  • 2. 两阶段锁协议
  • 3. 显式锁 — select … lock in share mode & for update
  • 4. MVCC
  • 5. 快照读和当前读
  • 6. MySQL 的隔离级别
  • 7. 事务隔离可能引起的问题
  • 8. mysql 修改事务隔离级别
  • 9. 查询全局和会话事务隔离级别
  • 10. 实例
    • 10.1. mysql 默认事务隔离等级
      • 10.2. Read Uncommitted
        • 10.3. Read Committed
          • 10.4. Repeatable Read
            • 10.5. Serializable
            相关产品与服务
            云数据库 SQL Server
            腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档