本文最后更新于7 天前,其中的信息可能已经过时,如有错误请发送邮件到PZ_0828@163.com
事务的本质
事务(Transaction) 是由一组数据库操作(DML语句)组成的逻辑单元,必须满足 ACID 特性,这些操作要么全部成功执行,要么全部失败回滚,从而保证数据库从一个一致的状态转换到另一个一致的状态,即使在系统发生故障或并发访问的情况下也是如此。
ACID 特性深度解析
1. 原子性(Atomicity)
- 核心:事务被视为一个不可分割的最小工作单元。事务中的所有操作要么全部成功提交(Commit),对数据库产生永久性影响;要么全部失败回滚(Rollback),数据库回退到事务开始前的状态,就像这个事务从未执行过一样。
- 重要性:保证不会有“部分完成”的事务,避免数据处于不一致的中间状态。例如银行转账操作必须同时成功扣款和入款,或者同时失败。
- 实现机制:通常利用回滚日志(Undo Log)来实现。事务执行期间的所有修改都会被记录到 Undo Log 中。如果事务失败或需要回滚,数据库引擎会利用 Undo Log 逆向执行操作,撤销所有修改。
- Undo Log:记录数据修改前的状态
- 失败时回滚:根据Undo Log逆向执行补偿操作
- 案例:
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1; -- 操作1
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2; -- 操作2
COMMIT; -- 若操作2失败,操作1自动撤销
2. 一致性(Consistency)
- 核心:事务执行的结果必须使数据库从一个一致性状态转变到另一个一致性状态。这里的“一致性”指的是数据库必须满足预定义的业务规则、约束和完整性(如主键唯一外键约束、数据类型、业务逻辑等)。简单来说,事务执行前后数据库必须处于合法状态(满足约束、触发器等规则)
- 重要性: 确保数据的有效性和正确性,符合现实世界的业务规则。
- 实现机制:
- 数据库内置约束(主键、唯一键、外键、CHECK约束)
- 应用层业务逻辑校验
- 案例:转账前后总金额不变(如
A-100 + B+100 = 原总额
)
3. 隔离性(Isolation)
- 核心:并发事务相互隔离,避免数据混乱。防止并发事务操作相同数据时导致的数据不一致问题(读现象)
- 重要性: 在高并发场景下保证数据的准确性和可靠性。
- 实现机制:主要通过锁机制(Locking)和多版本并发控制(MVCC-Multi-VersionConcurrency Control) 来实现。
4. 持久性(Durability)
- 核心:事务提交后数据永久存储(即使系统崩溃)
- 重要性:确保数据的可靠性,防止提交的操作丢失
- 实现机制:
- Redo Log:顺序记录物理修改(比写数据文件快100倍)
- 崩溃恢复:重启时重放Redo Log恢复未落盘数据
- 重做日志 (Redo Ldg):事务提交前,会先将所有修改以日志的形式顺序写入持久化的Redo Log 文件。即使数据库崩溃,重启后可以根据 Redo Log 重新执行(重做)那些已提交但尚未完全写入数据文件的操作,从而恢复数据
三、事务的底层实现技术
1. 锁机制
- 共享锁(S锁):读锁,允许多事务并发读
- 排他锁(X锁):写锁,独占数据访问权
- 锁粒度:
- 行级锁(InnoDB):
SELECT ... FOR UPDATE
- 表级锁(MyISAM):
LOCK TABLES table_name WRITE
- 行级锁(InnoDB):
2. MVCC(多版本并发控制)
- 核心思想:每个读操作看到数据的历史快照
- 实现关键:
- 隐藏列:
DB_TRX_ID
(事务ID)、DB_ROLL_PTR
(回滚指针) - Undo Log链:存储数据历史版本
- ReadView:判断哪些版本对当前事务可见# ReadView判断逻辑伪代码
def check_visibility(trx_id):
if trx_id < min_active_trx_id:
return True # 已提交事务
elif trx_id in active_trx_list:
return False # 未提交事务
else:
return trx_id <= creator_trx_id # 根据隔离级别决定
- 隐藏列:
总结
事务是保证数据操作安全的逻辑单元,核心是ACID
。原子性靠Undo Log
回滚,持久性依赖Redo Log
刷盘,隔离性通过锁和MVCC
实现,一致性是最终目标。