建网站app需要多少钱,网站上推广游戏怎么做的,找商务合作的平台,音乐制作网站简单来说#xff0c;MySQL 实现事务的核心就像是给你的数据库操作加了一套“保险和存档”机制。它确保了你的操作要么全部成功#xff0c;要么全部失败#xff0c;并且在面对多人同时操作、系统突然崩溃等情况时#xff0c;数据依然可靠、准确。
为什么需要事务呢#xff…简单来说MySQL 实现事务的核心就像是给你的数据库操作加了一套“保险和存档”机制。它确保了你的操作要么全部成功要么全部失败并且在面对多人同时操作、系统突然崩溃等情况时数据依然可靠、准确。
为什么需要事务呢想象一下银行转账你从A账户取出100元然后存入B账户。这其实是两个步骤
A账户余额 - 100元。B账户余额 100元。
如果第一个步骤成功了第二个步骤因为系统崩溃失败了那这100元就凭空消失了这显然不能接受。事务就是为了解决这类问题它把这些操作“打包”成一个不可分割的整体。
MySQL特别是其默认且最常用的存储引擎InnoDB通过以下“四大法宝”来确保事务的可靠性
原子性 (Atomicity)保证操作要么全成功要么全失败。一致性 (Consistency)保证事务前后数据都符合规则。隔离性 (Isolation)保证多个事务互不干扰像独立运行一样。持久性 (Durability)保证事务一旦提交数据就永远不会丢失。
接下来我们就一步一步揭开这些法宝的神秘面纱。一、 原子性 (Atomicity)要么全生要么全死
核心思想 事务里的所有操作就像一个“生死与共”的团队。要么这个团队所有成员都成功完成任务要么任务失败所有成员的状态都回到任务开始前就好像他们从来没做过一样。
MySQL 如何实现
MySQL 主要依靠 Undo Log回滚日志 来实现原子性。
想象一下你是一个艺术家正在画布上创作一幅画。每次你画一笔执行一个DML操作如UPDATE、DELETE、INSERT在动笔之前你都会把这一笔之前画布的样子用拍立得拍下来并贴在你的“回溯日记本”里。
如果你画得很顺利最终完成了你就可以把这些拍立得扔掉了事务提交Undo Log就不需要了。如果你画到一半发现画错了或者突然不想画了事务回滚或系统崩溃你就可以翻开“回溯日记本”找到最近一次拍的照片把画布恢复成那张照片的样子就好像你从未画错一样。
Undo Log 的作用
数据回滚 当事务回滚时InnoDB会读取Undo Log将数据恢复到事务开始前的状态。MVCC多版本并发控制 这是后面隔离性中会讲到的一个重要概念。Undo Log也保存了数据的历史版本供其他事务进行“快照读”。
事务提交/回滚的流程简化版
#mermaid-svg-D1PWnsvtzvPKHJjX {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-D1PWnsvtzvPKHJjX .error-icon{fill:#552222;}#mermaid-svg-D1PWnsvtzvPKHJjX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-D1PWnsvtzvPKHJjX .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-D1PWnsvtzvPKHJjX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-D1PWnsvtzvPKHJjX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-D1PWnsvtzvPKHJjX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-D1PWnsvtzvPKHJjX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-D1PWnsvtzvPKHJjX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-D1PWnsvtzvPKHJjX .marker.cross{stroke:#333333;}#mermaid-svg-D1PWnsvtzvPKHJjX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-D1PWnsvtzvPKHJjX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-D1PWnsvtzvPKHJjX .cluster-label text{fill:#333;}#mermaid-svg-D1PWnsvtzvPKHJjX .cluster-label span{color:#333;}#mermaid-svg-D1PWnsvtzvPKHJjX .label text,#mermaid-svg-D1PWnsvtzvPKHJjX span{fill:#333;color:#333;}#mermaid-svg-D1PWnsvtzvPKHJjX .node rect,#mermaid-svg-D1PWnsvtzvPKHJjX .node circle,#mermaid-svg-D1PWnsvtzvPKHJjX .node ellipse,#mermaid-svg-D1PWnsvtzvPKHJjX .node polygon,#mermaid-svg-D1PWnsvtzvPKHJjX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-D1PWnsvtzvPKHJjX .node .label{text-align:center;}#mermaid-svg-D1PWnsvtzvPKHJjX .node.clickable{cursor:pointer;}#mermaid-svg-D1PWnsvtzvPKHJjX .arrowheadPath{fill:#333333;}#mermaid-svg-D1PWnsvtzvPKHJjX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-D1PWnsvtzvPKHJjX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-D1PWnsvtzvPKHJjX .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-D1PWnsvtzvPKHJjX .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-D1PWnsvtzvPKHJjX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-D1PWnsvtzvPKHJjX .cluster text{fill:#333;}#mermaid-svg-D1PWnsvtzvPKHJjX .cluster span{color:#333;}#mermaid-svg-D1PWnsvtzvPKHJjX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-D1PWnsvtzvPKHJjX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}是否(例如: 错误/回滚)事务开始: T1执行SQL操作1: UPDATE 账户A记录原始值到Undo Log(例如: 账户A原值1000)执行SQL操作2: INSERT 交易记录记录原始值到Undo Log(例如: 交易记录无回滚则删除)所有操作完成?事务提交清空Undo Log操作生效并持久化(通过Redo Log等)事务回滚根据Undo Log恢复数据到事务开始前状态
专家视角 原子性是事务的基石。没有原子性一致性、隔离性和持久性都无从谈起。Undo Log不仅是实现原子性的关键它还是MVCC实现隔离性的重要支撑因为它存储了数据的历史版本。二、 一致性 (Consistency)万变不离其宗
核心思想 事务执行前后数据库的数据状态必须从一个一致性状态转换到另一个一致性状态。这意味着所有预设的规则比如账户余额不能为负数、订单号不能重复、外键关系不能被破坏等都必须得到遵守。
MySQL 如何实现
一致性不是由某个单一的机制直接实现的它是原子性、隔离性、持久性共同作用的结果加上数据库本身的约束和应用层的业务逻辑来保证的。
原子性 确保了要么所有操作成功要么都回滚避免了中间状态的暴露。隔离性 确保了并发操作时事务不会看到其他事务的中间状态从而避免了脏数据。持久性 确保了提交后的数据不会丢失也就不会导致数据不一致。数据库约束 PRIMARY KEY (主键)、UNIQUE KEY (唯一键)、FOREIGN KEY (外键)、NOT NULL (非空) 等。这些约束是数据库层面强制执行的规则。业务逻辑 应用程序代码中实现的复杂业务规则例如转账时检查账户余额是否充足。
一致性就像是建筑的蓝图。无论你对建筑进行什么操作加盖、拆除最终的结构都必须符合蓝图的规定比如承重墙不能拆安全门必须保留。如果操作导致不符合蓝图就必须撤销回滚。
一致性更多的是一个目标是数据库系统和应用系统共同维护的一种状态。它确保了数据的合法性和有效性。当原子性、隔离性、持久性都得到保障时数据自然倾向于保持一致性。三、 隔离性 (Isolation)井水不犯河水
核心思想 当多个事务同时操作数据库时每个事务都感觉自己是唯一在操作的。一个事务的中间状态对其他事务是不可见的就像它们被“隔离”在一个个独立的房间里。
MySQL 如何实现
隔离性是事务中最复杂的部分因为它需要在并发性和数据正确性之间找到平衡。MySQL (InnoDB) 主要通过两种机制来实现锁 (Locks)最直接的隔离手段通过“抢占资源”来避免冲突。
共享锁 (S Lock)多个事务可以同时持有用于读操作。排他锁 (X Lock)只有一个事务可以持有用于写操作会阻塞其他读写操作。粒度 表锁锁住整张表、行锁锁住特定行。InnoDB 默认使用行锁粒度更细并发性更高。多版本并发控制 (MVCC - Multi-Version Concurrency Control)
核心思想 允许多个事务同时读取数据的不同“版本”而不是直接阻塞。就像每次修改数据时都创建一个新版本旧版本仍然保留着供正在读取的事务使用。这大大提高了并发性能。MVCC 依赖
Undo Log 前面提到了存储着数据的历史版本。隐藏字段 InnoDB 每行数据都会增加几个隐藏字段
DB_TRX_ID记录最近一次修改该行的事务ID。DB_ROLL_PTR回滚指针指向该行上一个版本的Undo Log记录。DB_ROW_ID行ID如果表没有主键InnoDB会生成一个隐藏的主键。
Read View (读视图) 一个在事务开始时生成的“快照”决定当前事务能看到哪些版本的数据。它包含当前活跃的事务ID列表。MVCC 的工作原理快照读
当一个事务进行“快照读”普通SELECT语句时它不是直接读取最新的数据而是根据自己的 Read View 和数据的 DB_TRX_ID、DB_ROLL_PTR沿着Undo Log链条找到一个它“应该”看到的数据版本。
隔离级别 数据库标准定义了四种隔离级别隔离性从弱到强并发性从强到弱
读未提交 (Read Uncommitted)可以看到其他事务未提交的数据脏读。基本不用。读已提交 (Read Committed)只能看到其他事务已提交的数据。但同一个事务内多次读取可能看到不同结果不可重复读。Oracle 默认级别。可重复读 (Repeatable Read)同一个事务内多次读取同一数据会看到相同结果避免了不可重复读。但可能出现幻读行数变化。MySQL (InnoDB) 默认级别。
实现 事务开始时生成 Read View整个事务期间都用这个 Read View。
串行化 (Serializable)最高级别强制事务串行执行完全避免脏读、不可重复读、幻读。并发性能最低。
实现 对所有读操作加共享锁写操作加排他锁。MVCC 如何避免“不可重复读”和“幻读”
不可重复读 在“可重复读”隔离级别下MVCC通过 Read View 的固定来解决。事务T1开始时生成一个 Read View即使事务T2修改了数据并提交T1仍然通过自己的 Read View 看到T2修改前的数据版本从而实现了可重复读。幻读 MVCC只能解决快照读的幻读问题。对于当前读SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE仍然会存在。MySQL 在“可重复读”隔离级别下通过间隙锁 (Gap Lock) 和 Next-Key Lock (行锁间隙锁) 来彻底解决幻读问题。
MVCC 读取数据的流程图
#mermaid-svg-CtwWKNbYCmeZfdnh {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-CtwWKNbYCmeZfdnh .error-icon{fill:#552222;}#mermaid-svg-CtwWKNbYCmeZfdnh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CtwWKNbYCmeZfdnh .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-CtwWKNbYCmeZfdnh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CtwWKNbYCmeZfdnh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CtwWKNbYCmeZfdnh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CtwWKNbYCmeZfdnh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CtwWKNbYCmeZfdnh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CtwWKNbYCmeZfdnh .marker.cross{stroke:#333333;}#mermaid-svg-CtwWKNbYCmeZfdnh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CtwWKNbYCmeZfdnh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CtwWKNbYCmeZfdnh .cluster-label text{fill:#333;}#mermaid-svg-CtwWKNbYCmeZfdnh .cluster-label span{color:#333;}#mermaid-svg-CtwWKNbYCmeZfdnh .label text,#mermaid-svg-CtwWKNbYCmeZfdnh span{fill:#333;color:#333;}#mermaid-svg-CtwWKNbYCmeZfdnh .node rect,#mermaid-svg-CtwWKNbYCmeZfdnh .node circle,#mermaid-svg-CtwWKNbYCmeZfdnh .node ellipse,#mermaid-svg-CtwWKNbYCmeZfdnh .node polygon,#mermaid-svg-CtwWKNbYCmeZfdnh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CtwWKNbYCmeZfdnh .node .label{text-align:center;}#mermaid-svg-CtwWKNbYCmeZfdnh .node.clickable{cursor:pointer;}#mermaid-svg-CtwWKNbYCmeZfdnh .arrowheadPath{fill:#333333;}#mermaid-svg-CtwWKNbYCmeZfdnh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CtwWKNbYCmeZfdnh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CtwWKNbYCmeZfdnh .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-CtwWKNbYCmeZfdnh .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-CtwWKNbYCmeZfdnh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CtwWKNbYCmeZfdnh .cluster text{fill:#333;}#mermaid-svg-CtwWKNbYCmeZfdnh .cluster span{color:#333;}#mermaid-svg-CtwWKNbYCmeZfdnh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CtwWKNbYCmeZfdnh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}T1可见T1不可见T1可见T1不可见是否事务T1开始生成Read View(RV)T1执行SELECT(快照读)读取数据行D的最新版本比较D.DB_TRX_ID与RV活跃事务列表返回数据D给T1沿着D.DB_ROLL_PTR追溯到Undo Log中的上一版本比较上一版本D的DB_TRX_ID与RV活跃事务列表返回数据D给T1继续追溯到更早版本直到找到可见版本或无版本找到可见版本?数据对T1不可见
专家视角 隔离性是并发控制的核心挑战。MVCC的引入是数据库发展的重要里程碑它极大地提高了数据库的并发处理能力让读写操作可以在大部分情况下互不阻塞。锁和MVCC是互补的锁用于需要严格同步的“当前读”和写操作MVCC用于高性能的“快照读”。四、 持久性 (Durability)言出法随一字千金
核心思想 事务一旦提交它对数据库的所有修改就是永久性的。即使系统崩溃、断电这些修改也必须能够恢复不会丢失。
MySQL 如何实现
MySQL (InnoDB) 主要通过 Redo Log重做日志 和 WAL (Write-Ahead Logging) 机制来确保持久性。
想象一下你是一个重要的会议记录员。会议上做出的所有决定数据修改你不是等会议全部结束才整理成正式文件而是每当有一个新决定拍板时你立即用最快的速度记在一本“快速笔记”Redo Log上。这本笔记会定期同步到正式的“会议记录本”数据文件。
即使会议进行到一半突然停电你也可以根据这本“快速笔记”恢复到停电前所有的已批准决定而不会丢失任何内容。
Redo Log 的作用
崩溃恢复 当数据库在事务提交后、数据页还没来得及从内存刷写到磁盘时崩溃重启后可以通过Redo Log将这些已提交但未持久化的修改重新应用到数据文件中确保数据不丢。提高性能 Redo Log是顺序写入的速度非常快。它允许事务提交时只将Redo Log刷盘相对数据文件随机写磁盘更快而数据页的刷盘可以延迟进行。
Redo Log 刷盘策略 (InnoDB_flush_log_at_trx_commit)
0事务提交时Redo Log 写入日志缓冲区并每秒刷盘一次。性能好但可能丢失1秒数据。1事务提交时Redo Log 写入日志缓冲区并立即刷盘。安全性最高但性能最差。2事务提交时Redo Log 写入日志缓冲区然后写到OS CacheOS每秒刷盘一次。折中方案。
WAL (Write-Ahead Logging) 原则
先写日志再写数据。即 Redo Log 必须先于对应的数据页刷盘。这是确保持久性的关键原则。
Double Write Buffer双写缓冲区
这是一个额外的保护机制防止“部分写失效”问题。当数据页从Buffer Pool刷写到磁盘时不是直接写到数据文件而是先写到Double Write Buffer一个连续的区域然后再写到真正的数据文件。这样即使在数据页写入过程中发生崩溃也可以从Double Write Buffer中恢复完整的数据页。
持久化流程图
#mermaid-svg-ozqAxuQ0Q0Kzh69s {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .error-icon{fill:#552222;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .marker.cross{stroke:#333333;}#mermaid-svg-ozqAxuQ0Q0Kzh69s svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .cluster-label text{fill:#333;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .cluster-label span{color:#333;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .label text,#mermaid-svg-ozqAxuQ0Q0Kzh69s span{fill:#333;color:#333;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .node rect,#mermaid-svg-ozqAxuQ0Q0Kzh69s .node circle,#mermaid-svg-ozqAxuQ0Q0Kzh69s .node ellipse,#mermaid-svg-ozqAxuQ0Q0Kzh69s .node polygon,#mermaid-svg-ozqAxuQ0Q0Kzh69s .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .node .label{text-align:center;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .node.clickable{cursor:pointer;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .arrowheadPath{fill:#333333;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .cluster text{fill:#333;}#mermaid-svg-ozqAxuQ0Q0Kzh69s .cluster span{color:#333;}#mermaid-svg-ozqAxuQ0Q0Kzh69s div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ozqAxuQ0Q0Kzh69s :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}是已提交未刷盘数据页未提交事务客户端提交事务数据修改(在内存Buffer Pool中)将修改内容写入Redo Log Buffer(内存中)事务提交Redo Log Buffer内容刷写到磁盘Redo Log文件(遵循WAL原则)事务提交成功返回客户端后台线程异步将Buffer Pool中修改过的数据页刷写到磁盘数据文件(可能通过Double Write Buffer)数据库崩溃/断电数据库重启检查Redo Log文件发现未完全刷盘的已提交事务或未完成的事务?通过Redo Log重做这些操作恢复数据一致性通过Undo Log回滚这些操作数据库恢复完成对外服务
持久性是数据库系统最重要的承诺之一。Redo Log和WAL机制是实现这一承诺的核心它们在保证数据不丢失的同时也通过日志的顺序写入特性提升了性能。数据库的恢复能力是其健壮性的重要体现。MySQL (InnoDB) 实现事务的四大特性是一套精妙且协同工作的复杂系统。它不是依靠单一技术而是通过多种机制的组合与协作
Undo Log是原子性回滚和隔离性MVCC 多版本的基石。Redo Log是持久性崩溃恢复和高性能写入的保障。锁机制是隔离性的直接手段解决并发冲突特别是“当前读”的隔离。MVCC是隔离性的高级实现通过多版本数据和 Read View 提升并发性能。WAL原则、Double Write Buffer、事务隔离级别、数据库约束等都是这套系统的重要组成部分。