事务与并发控制
第十三章:事务与并发控制
💡 事务是数据库操作的基本单位,并发控制保证多用户同时访问时的数据一致性
13.1 事务概念
13.1.1 什么是事务
定义:事务是作为单个逻辑工作单元执行的一系列操作,这些操作要么全部成功,要么全部失败。
13.1.2 事务的四大特性(ACID)
| 特性 |
英文 |
说明 |
保证方式 |
| 原子性 |
Atomicity |
事务中的操作要么全部完成,要么全部不完成 |
Undo Log |
| 一致性 |
Consistency |
事务前后,数据库从一个一致状态转到另一个一致状态 |
其他三个特性保证 |
| 隔离性 |
Isolation |
并发事务之间相互隔离,互不干扰 |
锁机制、MVCC |
| 持久性 |
Durability |
事务提交后,修改永久保存 |
Redo Log |
13.2 事务控制语句
13.2.1 基本语法
START TRANSACTION;
BEGIN;
COMMIT;
ROLLBACK;
SAVEPOINT 保存点名称;
ROLLBACK TO SAVEPOINT 保存点名称;
RELEASE SAVEPOINT 保存点名称;
13.2.2 事务示例:银行转账
START TRANSACTION;
SELECT 余额 INTO @balance FROM 账户 WHERE 账户号 = 'A';
IF @balance < 500 THEN
SELECT '余额不足' AS 结果;
ROLLBACK;
ELSE
UPDATE 账户 SET 余额 = 余额 - 500 WHERE 账户号 = 'A';
UPDATE 账户 SET 余额 = 余额 + 500 WHERE 账户号 = 'B';
COMMIT;
SELECT '转账成功' AS 结果;
END IF;
13.2.3 保存点示例
START TRANSACTION;
INSERT INTO 订单 VALUES (1, '客户A', NOW());
SAVEPOINT sp1;
INSERT INTO 订单明细 VALUES (1, '商品1', 10);
SAVEPOINT sp2;
INSERT INTO 订单明细 VALUES (1, '商品2', 20);
ROLLBACK TO SAVEPOINT sp2;
COMMIT;
13.3 自动提交模式
13.3.1 查看和设置自动提交
SELECT @@autocommit;
SHOW VARIABLES LIKE 'autocommit';
SET autocommit = 0;
SET autocommit = 1;
13.3.2 自动提交 vs 显式事务
| 模式 |
说明 |
使用场景 |
| 自动提交(默认) |
每条SQL语句自动成为一个事务 |
单条语句操作 |
| 显式事务 |
使用BEGIN/COMMIT/ROLLBACK控制 |
多条语句需要原子操作 |
| 关闭自动提交 |
每次操作需要手动COMMIT |
批量操作、需要回滚控制 |
13.4 事务隔离级别
13.4.1 并发问题
| 问题 |
说明 |
示例 |
| 脏读 |
读取到其他事务未提交的数据 |
A修改数据但未提交,B读取到了 |
| 不可重复读 |
同一事务内两次读取结果不同 |
A两次读取之间,B修改并提交了 |
| 幻读 |
同一事务内两次查询结果集不同 |
A两次查询之间,B插入了新数据 |
13.4.2 四种隔离级别
| 隔离级别 |
脏读 |
不可重复读 |
幻读 |
性能 |
| READ UNCOMMITTED |
✓可能 |
✓可能 |
✓可能 |
最高 |
| READ COMMITTED |
✗避免 |
✓可能 |
✓可能 |
较高 |
| REPEATABLE READ(MySQL默认) |
✗避免 |
✗避免 |
✓可能 |
中等 |
| SERIALIZABLE |
✗避免 |
✗避免 |
✗避免 |
最低 |
13.4.3 设置隔离级别
SELECT @@transaction_isolation;
SELECT @@tx_isolation;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
13.4.4 隔离级别示例
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
SELECT * FROM 账户 WHERE 账户号 = 'A';
START TRANSACTION;
UPDATE 账户 SET 余额 = 500 WHERE 账户号 = 'A';
SELECT * FROM 账户 WHERE 账户号 = 'A';
ROLLBACK;
13.5 锁机制
13.5.1 锁的类型
| 锁类型 |
说明 |
兼容性 |
| 共享锁(S锁/读锁) |
允许多个事务同时读取 |
与其他S锁兼容 |
| 排他锁(X锁/写锁) |
只允许一个事务独占 |
与任何锁都不兼容 |
13.5.2 锁的粒度
| 粒度 |
说明 |
优点 |
缺点 |
| 表锁 |
锁定整个表 |
开销小,加锁快 |
并发度低 |
| 行锁 |
锁定单行 |
并发度高 |
开销大,可能死锁 |
13.5.3 InnoDB 行锁
SELECT * FROM 表名 WHERE 条件 LOCK IN SHARE MODE;
SELECT * FROM 表名 WHERE 条件 FOR SHARE;
SELECT * FROM 表名 WHERE 条件 FOR UPDATE;
START TRANSACTION;
SELECT * FROM 账户 WHERE 账户号 = 'A' FOR UPDATE;
UPDATE 账户 SET 余额 = 余额 - 100 WHERE 账户号 = 'A';
COMMIT;
13.5.4 死锁
死锁检测和处理:
SHOW ENGINE INNODB STATUS\G
SELECT * FROM information_schema.INNODB_LOCK_WAITS;
SELECT * FROM information_schema.INNODB_LOCKS;
13.6 事务最佳实践
13.6.1 事务设计原则
| 原则 |
说明 |
| 事务尽量短 |
长事务会占用资源,增加锁冲突 |
| 避免交互式事务 |
不要在事务中等待用户输入 |
| 合理选择隔离级别 |
根据业务需求选择适当的隔离级别 |
| 处理死锁 |
设计时避免死锁,程序中处理死锁异常 |
| 使用索引 |
避免表锁,减少锁范围 |
13.6.2 事务示例:完整的转账存储过程
DELIMITER //
CREATE PROCEDURE transfer(
IN from_account VARCHAR(20),
IN to_account VARCHAR(20),
IN amount DECIMAL(10,2),
OUT result VARCHAR(50)
)
BEGIN
DECLARE from_balance DECIMAL(10,2);
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SET result = '转账失败:系统错误';
END;
START TRANSACTION;
SELECT 余额 INTO from_balance
FROM 账户
WHERE 账户号 = from_account
FOR UPDATE;
IF from_balance IS NULL THEN
SET result = '转账失败:账户不存在';
ROLLBACK;
ELSEIF from_balance < amount THEN
SET result = '转账失败:余额不足';
ROLLBACK;
ELSE
UPDATE 账户 SET 余额 = 余额 - amount
WHERE 账户号 = from_account;
UPDATE 账户 SET 余额 = 余额 + amount
WHERE 账户号 = to_account;
COMMIT;
SET result = '转账成功';
END IF;
END //
DELIMITER ;
CALL transfer('A', 'B', 500, @result);
SELECT @result;
13.7 快速参考
START TRANSACTION;
COMMIT;
ROLLBACK;
SAVEPOINT 名称;
ROLLBACK TO SAVEPOINT 名称;
SELECT @@autocommit;
SET autocommit = 0;
SELECT @@transaction_isolation;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT ... LOCK IN SHARE MODE;
SELECT ... FOR UPDATE;
⬅️ 用户管理与权限控制 🏠 00-数据库 ➡️ 01-PostgreSQL 基础与 MySQL 对照
💬 评论