欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 资讯 > MySQL:事务

MySQL:事务

2025/4/18 21:21:43 来源:https://blog.csdn.net/lyy42995004/article/details/147088648  浏览:    关键词:MySQL:事务

在 MySQL 数据库中,事务是确保数据一致性和完整性的重要机制。它允许将一系列数据库操作作为一个不可分割的整体进行处理,要么全部成功执行,要么全部回滚。

特性 (ACID)

原子性(Atomicity)

  • 概念:原子性确保事务是一个不可分割的工作单元。事务中的所有操作要么全部成功执行,要么全部回滚。

  • 实现:MySQL 通过undo log回滚日志来实现原子性。当事务执行过程中出现错误或被回滚时,undo log记录的信息可用于撤销已经执行的操作,将数据库恢复到事务开始前的状态。

一致性(Consistency)

  • 概念:一致性要求事务执行前后,数据库的完整性约束没有被破坏,数据从一个一致状态转换到另一个一致状态。

  • 实现:一致性的实现依赖于原子性、隔离性和持久性的共同作用。原子性保证操作的完整性,隔离性防止并发干扰,持久性确保提交后的结果稳定,从而共同保障数据的一致性。

隔离性(Isolation)

  • 概念:隔离性指多个事务并发执行时,一个事务的执行不能被其他事务干扰。

  • 实现:MySQL 通过多版本并发控制(MVCC)和锁机制来实现隔离性。MVCC 为每个事务构建数据快照,使其在执行期间看到的数据一致;锁机制则通过对数据加锁,限制其他事务的访问。不同的隔离级别对并发事务的隔离程度不同,从而影响数据的一致性和系统的并发性能。

持久性(Durability)

  • 概念:持久性表示事务一旦提交,它对数据库所做的修改就会永久保存到数据库中,即使数据库发生故障也不会丢失。

  • 实现:MySQL 利用redo log重做日志来实现持久性。当事务提交时,相关修改先记录到redo log中,后续再将数据持久化到磁盘。在数据库重启或发生故障时,可依据redo log中的记录恢复数据,确保事务的持久性。

并发问题

image.png

脏读:脏读是指一个事务读取到了其他事务未提交的数据。

例如,事务 A 对某条数据进行修改但未提交,此时事务 B 读取了这条被修改但未提交的数据,若事务 A 最终回滚,事务 B 读取的数据就是无效的,这就产生了脏读问题。脏读会导致数据的不一致和不可靠。

不可重复读:不可重复读是指在同一个事务中,相同的查询操作在不同时间返回不同的结果。

例如,事务 A 在查询某条数据后,事务 B 对该数据进行修改并提交,当事务 A 再次执行相同查询时,得到的结果与第一次不同。不可重复读主要是由于其他事务对数据的修改导致的。

幻读:幻读是指在一个事务中,两次相同的查询条件下,查询到的结果集数量不一致,仿佛出现了 “幻影” 行。

例如,事务 A 查询满足某条件的记录数量,事务 B 在事务 A 两次查询之间插入了满足该条件的新记录并提交,事务 A 再次查询时记录数量增加,就产生了幻读现象。

隔离级别

image.png

image.png

隔离级别特点能否解决脏读不可重复读幻读
读未提交(Read Uncommitted)可读取其他事务未提交的数据
读已提交(Read Committed)只读取已提交事务的数据
可重复读(Repeatable Read)(InnoDB默认)同一事务多次读取一致⚠️(使用MVCC避免)
串行化(Serializable)强制串行执行事务

InnoDB在"可重复读"级别通过Next-Key Lock解决了幻读问题

MVCC机制解析

Read View: MVCC 的核心概念,用于判断一个事务对数据的可见。

在不同隔离级别下,Read View 的生成时机不同。读提交隔离级别每次查询时生成 Read View,可重复读隔离级别在启动事务时生成 Read View。

什么是 Read View?

  • Read View 是事务读取数据时创建的“视图”;
  • 用于生成数据的“快照”,实现一致性读取;
  • 不同事务生成的 Read View 不同。
struct read_view_t {trx_id_t    creator_trx_id;  // 创建该视图的事务IDids_t       m_ids;          // 活跃事务ID列表trx_id_t    min_trx_id;     // 最小活跃事务IDtrx_id_t    max_trx_id;     // 预分配的下个事务ID
};

image.png

image.png

隐藏列

InnoDB 存储引擎中的每个数据行都包含一些隐藏列,其中

  • trx_id记录了该数据发生改变时事务的id值。

  • roll_pointer是指向旧版本数据的指针,用于undo log回溯。

工作原理:当事务查询数据时,依据 Read View 和隐藏列中的trx_id判断数据的可见性。

  1. trx_id < min_trx_id,说明事务已提交,当前事务该数据可见。
  2. trx_id >= min_trx_id,表示事务未提交,当前事务该数据不可见。
  3. min_trx_id < trx_id < max_trx_id时,若trx_idm_ids中,说明事务未提交,该数据不可见;若trx_id不在m_ids中,表明事务已提交,该数据可见。
  4. 在不同隔离级别下,Read View 的生成时机不同。读提交隔离级别每次查询时生成 Read View,可重复读隔离级别在启动事务时生成 Read View。

image.png

快照读 vs 当前读

类型描述使用场景
快照读使用 Read View 查看历史版本数据,不加锁SELECT 查询
当前读直接读取最新记录,使用加锁机制SELECT ... FOR UPDATEUPDATEDELETE

长事务问题

问题

  • 锁竞争阻塞资源:长事务长时间持有锁,会阻塞其他事务对相关资源的访问,降低系统的并发性能。
  • 死锁风险:多个长事务可能相互等待对方释放锁,从而导致死锁。
  • 主从延迟:在主从复制架构中,长事务执行时间长,从库需要花费更多时间重放主库的事务操作,导致主从之间长时间数据不同步,影响数据的实时性。
  • 回滚导致时间浪费:长事务执行时间长,若因某些原因需要回滚,回滚操作也会耗费大量时间,造成资源浪费。

解决

  • 拆分事务:尽量将 SQL 拆分为多个短事务。
  • 控制事务粒度:减少单个事务处理的数据量。
  • 及时提交事务:防止持有太久的 undo log。
  • 使用合适的隔离级别:避免不必要的加锁操作。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词