Appearance
事务处理
事务概述
事务是一组数据库操作的逻辑单元,要么全部成功,要么全部失败。
ACID 特性
| 特性 | 说明 |
|---|---|
| 原子性 (Atomicity) | 事务是不可分割的工作单位 |
| 一致性 (Consistency) | 事务前后数据保持一致状态 |
| 隔离性 (Isolation) | 多个事务互不干扰 |
| 持久性 (Durability) | 事务提交后永久保存 |
事务控制
基本语法
sql
START TRANSACTION;
BEGIN;
COMMIT;
ROLLBACK;示例
sql
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;保存点
sql
START TRANSACTION;
INSERT INTO orders (user_id, amount) VALUES (1, 100);
SAVEPOINT sp1;
INSERT INTO order_items (order_id, product_id) VALUES (1, 1);
SAVEPOINT sp2;
ROLLBACK TO sp1;
COMMIT;隔离级别
四种隔离级别
| 级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | ✓ | ✓ | ✓ |
| READ COMMITTED | ✗ | ✓ | ✓ |
| REPEATABLE READ | ✗ | ✗ | ✓ |
| SERIALIZABLE | ✗ | ✗ | ✗ |
查看隔离级别
sql
SELECT @@transaction_isolation;
SELECT @@global.transaction_isolation;设置隔离级别
sql
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;各隔离级别详解
READ UNCOMMITTED(读未提交)
sql
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;可能读取到其他事务未提交的数据(脏读)。
READ COMMITTED(读已提交)
sql
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;只能读取已提交的数据,但可能出现不可重复读。
REPEATABLE READ(可重复读)
sql
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;MySQL 默认隔离级别,同一事务中多次读取结果相同。
SERIALIZABLE(串行化)
sql
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;最高隔离级别,完全串行执行,性能最低。
并发问题
脏读
读取到其他事务未提交的数据。
事务A: UPDATE users SET age = 30 WHERE id = 1;
事务B: SELECT age FROM users WHERE id = 1; -- 读取到 30
事务A: ROLLBACK; -- age 实际未改变不可重复读
同一事务中两次读取结果不同。
事务A: SELECT age FROM users WHERE id = 1; -- 25
事务B: UPDATE users SET age = 30 WHERE id = 1; COMMIT;
事务A: SELECT age FROM users WHERE id = 1; -- 30幻读
同一事务中两次查询记录数不同。
事务A: SELECT * FROM users WHERE age > 20; -- 5条
事务B: INSERT INTO users (age) VALUES (25); COMMIT;
事务A: SELECT * FROM users WHERE age > 20; -- 6条锁机制
锁类型
| 锁类型 | 说明 |
|---|---|
| 共享锁 (S) | 读锁,允许多个事务同时读取 |
| 排他锁 (X) | 写锁,独占资源 |
| 意向锁 | 表级锁,表示事务意图 |
行级锁
sql
SELECT * FROM users WHERE id = 1 FOR UPDATE;
SELECT * FROM users WHERE id = 1 LOCK IN SHARE MODE;
SELECT * FROM users WHERE id = 1 FOR SHARE;表级锁
sql
LOCK TABLES users READ;
LOCK TABLES users WRITE;
UNLOCK TABLES;间隙锁
sql
SELECT * FROM users WHERE id BETWEEN 1 AND 10 FOR UPDATE;临键锁 (Next-Key Lock)
InnoDB 在 REPEATABLE READ 级别下使用临键锁防止幻读。
死锁
死锁示例
事务A: UPDATE users SET age = 1 WHERE id = 1;
事务B: UPDATE users SET age = 2 WHERE id = 2;
事务A: UPDATE users SET age = 3 WHERE id = 2; -- 等待
事务B: UPDATE users SET age = 4 WHERE id = 1; -- 死锁查看死锁
sql
SHOW ENGINE INNODB STATUS;避免死锁
- 按相同顺序访问表和行
- 避免长事务
- 使用较低的隔离级别
- 合理设计索引
事务日志
Redo Log(重做日志)
保证事务持久性,崩溃恢复时使用。
sql
SHOW VARIABLES LIKE 'innodb_log%';Undo Log(回滚日志)
保证事务原子性,用于回滚和 MVCC。
sql
SHOW VARIABLES LIKE 'innodb_undo%';Binlog(二进制日志)
用于主从复制和增量备份。
sql
SHOW VARIABLES LIKE 'log_bin%';
SHOW BINARY LOGS;MVCC 多版本并发控制
实现原理
- 每行数据包含隐藏列:DB_TRX_ID、DB_ROLL_PTR
- Undo Log 保存历史版本
- Read View 决定可见性
Read View
| 字段 | 说明 |
|---|---|
| m_ids | 活跃事务ID列表 |
| min_trx_id | 最小活跃事务ID |
| max_trx_id | 下一个事务ID |
| creator_trx_id | 创建者事务ID |
可见性判断
如果 DB_TRX_ID < min_trx_id:可见
如果 DB_TRX_ID >= max_trx_id:不可见
如果 DB_TRX_ID 在 m_ids 中:不可见
否则:可见