概述MySQL事务隔离级别类型

本文深入探讨MySQL中的锁机制,包括表锁和行锁的特点及应用,以及InnoDB和MyISAM存储引擎的区别。同时,详细解析事务的四大特性:原子性、一致性、隔离性和持久性,并分析在并发场景下可能遇到的事务问题,如更新丢失、脏读、不可重读和幻读。最后,对比MySQL四种事务隔离级别的优缺点,指导合理选择。

MySQL中锁的类型

表锁

      顾名思义,也就是每次对一张表进行操作的时候会锁住整张表,这样加锁的速度更快,但是加锁的粒度太大,发生锁冲突的概率回很高,所以表锁的并发效率不高

如何给表加锁以及差查那些表已经被上锁:

lock table 表名称 read(write),表名称2 read(write)--加锁
unlock tables; --解锁
show open tables; --查看被加锁的表

表锁的特性:

  • 如果加的是读锁,那么会阻塞其他事务的更新、插入操作,但是不会阻塞读取
  • 如果加的是写锁,无论什么操作都是会阻塞,直到另一个事务解锁,才会执行后面的事务语句
     很重要的一点是 MyISAM存储引擎 在执行查询语句的时候会自动给涉及到的表加读锁,增删改操作会给表加写锁。

行锁

    行锁就是锁住表中某一行数据,相比于表锁他的开销大,效率也稍微弱一点,但是锁的粒度小,相对的并发度也很高

InnoDB和MyISAM存储引擎最大的区别就是:InnoDB支持行锁和事务,这两点MyISAM是没有的。

行锁事务属性

  1. 原子性(Atomicity)
    也就是在一个事务中的一组SQL语句要一起执行完或者都失败,它们是一个整体,强调动作
  2. 一致性(Consistent)
    在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的,强调动作之后的结果
  3. 隔离性(Isolation)
    数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的。简单说每个事务都是不能被其他事务影响。
  4. 持久性(Durable)
    事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持

 

那么在并发场景下会出现那些事务问题

  1. 更新丢失
    在两个事务A、B读取数据库的时候,都读取到初始值,A事务先更新,B事务后更新,这时候B事务就会将A事务更新的结果覆盖掉
  2. 脏读
    同样是两个事务,A事务在对数据做更新的时候并未提交数据,这时候B事务读取到了A未提交的数据,这种情况下一旦事务A回滚事务,那么B事务的数据就变成了脏数据。
  3. 不可重读
    A事务在读取数据后的某个时间,重新读取了这条数据,但是这条数据已经被其他数据修改了,但是这时候A事务还没结束,这就不符合事务的隔离性,这就是不可重读的问题,简单说就是读取到了其他事务已经提交的更新操作
  4. 幻读
    一个事务使用一条查询语句重新查询时发现两次的结果不一致,因为其他事务在这个条件中插入了数据, 也就是说事务A读取到了事务B提交的新增数据,同样也是不符合隔离性

 

MySQL的事务隔离级别

事务隔离级别脏读不可重读幻读
读未提交(read-uncommitted)可能可能可能
读已提交(read-committed)不可能可能可能
可重读(repeatable-read)不可能不可能可能
串行化(serializable)不可能不可能不可能

 

    表中横排是可能出现的事务问题,竖排是MySQL存在是隔离级别,因为对于重读的问题,最大只能支持到已提交的更新,也就是说:可重读的事务隔离级别下是不会出现读取到其他事务中已经提交更新的数据。因为幻读是一个特殊的情况 他是已提交的插入操作,只有串行化才能解决,但是一旦用了串行话MySQ的性能就相对没有可重读那样高。综合考虑一般情况下都是使用可重读的事务隔离级别

查看当前数据库的事务隔离级别: show variables like 'tx_isolation';
设置事务隔离级别:set tx_isolation='REPEATABLE-READ';

可重复读的验证

1、开启事务START TRANSACTION,并查询当前表中数据

  1. 打开另一个客户端开启事务,更新表并提交:
update account set balance = balance - 50 where id = 2

   客户端B已经查询到更新后的数据是:850

 

这时客户端B的数据已经更新,但是客户端A再次查询是没有查询到更新后的数据

那么这时候在客户端A操作更新语句会是什么情况?是850吗?

update account set balance = balance - 50 where id = 2

按照实际操作来看,在更新的时候没有变成900-50 = 850,而是读取到了事务B已经提交的结果。这样数据一致性的机制没有被破坏。

<think> 嗯,用户希望了解MySQL事务隔离级别的具体实现方式。需要结合站内引用的内容作答。 用户引用了三段材料: 第一段提到如何设置事务隔离级别的SQL语法,说明用户关心实际操作层面。 第二段解释了多会话并发访问时隔离性的重要性,提到性能与隔离性的平衡。 第三段列出了四种隔离级别及其现象,是核心分类依据。 用户明确询问"具体实现方式",因此需要深入底层机制而非概念性描述。考虑从几个技术点展开: 1. 锁机制(记录锁、间隙锁、Next-Key锁),这是实现隔离性的基础 2. MVCC多版本并发控制,这是InnoDB的核心技术 3. 不同隔离级别的实现差异,特别是可重复读如何避免幻读 用户似乎具备一定数据库知识(能准确说出"事务隔离级别"术语),但未提引擎细节,回答需要兼顾深度和可读性。InnoDB作为默认引擎应作为重点。 注意到用户引用的材料三出现"可重复读可能会幻读"的表述,这与MySQL实际实现有出入——InnoDB在可重复读下通过Next-Key锁避免了幻读。这点需要特别澄清,避免误解。 回答结构上,先概述实现原理(锁+MVCC),再分隔离级别解释,最后总结引擎差异。技术细节如版本链、ReadView需要简明图解,考虑用表格对比各隔离级别的锁策略和MVCC使用情况。 </think>MySQL事务隔离级别的具体实现主要依赖于**锁机制**和**多版本并发控制(MVCC)** 两种核心技术,不同隔离级别通过调整这两种技术的使用策略来实现[^2][^3]。以下是关键实现细节: --- ### **一、核心实现机制** 1. **锁机制 (Locking)** * **共享锁 (S Lock)**:读锁,允许多事务并发读取同一数据。 * **排他锁 (X Lock)**:写锁,仅允许持有锁的事务修改数据,其他事务无法读写。 * **间隙锁 (Gap Lock)**:锁定索引记录间的“间隙”,防止其他事务在范围内插入新数据(解决幻读)。 * **Next-Key Lock**:InnoDB默认锁,**组合记录锁 + 间隙锁**(如锁定`10`及`(5,10)`区间)。 2. **多版本并发控制 (MVCC)** * 每行数据隐藏两个字段:`DB_TRX_ID`(最近修改的事务ID)和`DB_ROLL_PTR`(指向旧版本数据的回滚指针)。 * 通过**版本链(Undo Log)** 存储历史版本,读操作根据隔离级别访问对应版本。 * **ReadView**:事务开启时生成的数据快照,决定可见哪些版本: - `m_ids`:活跃事务ID列表 - `min_trx_id`:最小活跃事务ID - `max_trx_id`:预分配的下个事务ID - `creator_trx_id`:当前事务ID --- ### **二、不同隔离级别的具体实现** | 隔离级别 | 锁策略 | MVCC策略 | 解决并发问题 | |-------------------|----------------------------------|--------------------------------------------------------------------------|----------------------------------| | **READ UNCOMMITTED** | 不加读锁,写时加排他锁 | ❌ **不使用MVCC**,直接读最新数据(含未提交) | ❌ 脏读、不可重复读、幻读 | | **READ COMMITTED** | 写时加排他锁;读不加锁,但每次读新快照 | ✅ **每次SELECT生成新ReadView**,仅读已提交数据 | ✅ 脏读<br>❌ 不可重复读、幻读 | | **REPEATABLE READ** | 写时加排他锁 + Next-Key锁 | ✅ **首次SELECT生成ReadView**,后续读复用该快照 | ✅ 脏读、不可重复读<br>✅ InnoDB解决幻读(Next-Key锁) | | **SERIALIZABLE** | 所有读加共享锁,写加排他锁 | ⚠️ **退化为锁控制**,MVCC失效 | ✅ 所有问题(性能最低) | --- ### **三、关键实现细节** 1. **可重复读 (REPEATABLE READ) 如何避免幻读?** InnoDB通过**Next-Key锁**锁定查询范围(如`WHERE id > 10`会锁`(10, +∞)`),阻止其他事务在范围内插入数据[^3]。 2. **读已提交 (READ COMMITTED) 与 MVCC** 每次`SELECT`生成新ReadView,因此能看到其他事务已提交的新数据。 3. **版本链访问规则** 数据可见性由`DB_TRX_ID`和ReadView决定: ```plaintext if DB_TRX_ID < min_trx_id : 可见(已提交) if DB_TRX_ID > max_trx_id : 不可见(未来事务) if min_trx_id ≤ DB_TRX_ID ≤ max_trx_id : 若 DB_TRX_ID ∈ m_ids → 不可见(未提交) 否则 → 可见(已提交) ``` --- ### **四、示例说明** ```sql -- 事务A (REPEATABLE READ) START TRANSACTION; SELECT * FROM users WHERE age > 20; -- 生成ReadView,返回2条记录 -- 事务B 插入新数据并提交 INSERT INTO users (name, age) VALUES ('Bob', 25); COMMIT; -- 事务A 再次查询(复用原ReadView) SELECT * FROM users WHERE age > 20; -- 仍返回2条,避免幻读 ``` > 事务A的第二次查询: > - 若隔离级别为`READ COMMITTED` → 看到新插入的`Bob`(幻读) > - 若为`REPEATABLE READ` → 因Next-Key锁阻止插入,且ReadView不变 → 结果一致 --- ### **总结** MySQL事务隔离级别通过**锁粒度控制**和**MVCC版本可见性规则**实现: 🔒 **低隔离级别(READ UNCOMMITTED/COMMITTED)**:偏向MVCC,锁开销小但一致性弱。 🔐 **高隔离级别(REPEATABLE READ/SERIALIZABLE)**:加强锁机制(尤其Next-Key锁),保证强一致性但影响并发性能[^2][^3]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值