<返回目录     Powered by claud/xia兄

第11课: 事务处理

ACID特性、事务隔离级别、锁机制

事务基础概念

什么是事务?

事务是一组数据库操作,它们要么全部成功执行,要么全部失败回滚,是数据库操作的最小工作单元。事务确保了数据操作的一致性和可靠性。

事务的ACID特性

事务ACID特性示意图
特性 说明 重要性
Atomicity(原子性) 事务是不可分割的工作单元,要么全部成功,要么全部失败回滚 确保数据操作的完整性,避免部分执行导致的数据不一致
Consistency(一致性) 事务执行前后,数据库从一个一致性状态转变为另一个一致性状态 保证业务规则和数据完整性约束不被破坏
Isolation(隔离性) 多个事务并发执行时,一个事务的执行不应影响其他事务的执行 防止并发事务相互干扰,确保数据一致性
Durability(持久性) 事务一旦提交,其结果就是永久性的,即使系统崩溃也不会丢失 保证数据的持久存储,防止数据丢失

事务控制语句

-- 示例1: 开始事务
START TRANSACTION;
BEGIN;  -- 简写形式

-- 示例2: 提交事务
COMMIT;

-- 示例3: 回滚事务
ROLLBACK;

-- 示例4: 保存点
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
SAVEPOINT transfer;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- 如果出错,可以回滚到保存点
ROLLBACK TO transfer;
-- 否则提交
COMMIT;

自动提交模式

-- 查看自动提交状态
SHOW VARIABLES LIKE 'autocommit';

-- 禁用自动提交
SET autocommit = 0;

-- 启用自动提交
SET autocommit = 1;

事务隔离级别

事务隔离级别定义了并发事务之间的隔离程度,不同的隔离级别会影响并发性能和数据一致性。

事务隔离级别对比图
隔离级别 脏读 不可重复读 幻读 并发性能 适用场景
READ UNCOMMITTED(读未提交) 可能 可能 可能 最高 对数据一致性要求低的场景
READ COMMITTED(读已提交) 不可能 可能 可能 大多数应用场景
REPEATABLE READ(可重复读) 不可能 不可能 可能 对数据一致性要求较高的场景
SERIALIZABLE(串行化) 不可能 不可能 不可能 最低 对数据一致性要求极高的场景

设置隔离级别

-- 会话级别设置
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 全局级别设置
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 查看当前隔离级别
SELECT @@tx_isolation;
SELECT @@global.tx_isolation;

-- MySQL 8.0+
SELECT @@transaction_isolation;
SELECT @@global.transaction_isolation;

并发问题

并发事务可能导致的问题:
-- 脏读(Dirty Read):读取到其他事务未提交的数据
-- 事务A
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- 未提交

-- 事务B
SELECT balance FROM accounts WHERE id = 1;  -- 读取到未提交的数据

-- 不可重复读(Non-repeatable Read):同一事务中多次读取同一数据,结果不同
-- 事务A
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 1;  -- 1000

-- 事务B
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;

-- 事务A
SELECT balance FROM accounts WHERE id = 1;  -- 900(与第一次读取不同)
COMMIT;

-- 幻读(Phantom Read):同一事务中多次查询同一范围的数据,结果集不同
-- 事务A
START TRANSACTION;
SELECT COUNT(*) FROM accounts WHERE balance > 500;  -- 5

-- 事务B
START TRANSACTION;
INSERT INTO accounts (balance) VALUES (600);
COMMIT;

-- 事务A
SELECT COUNT(*) FROM accounts WHERE balance > 500;  -- 6(与第一次读取不同)
COMMIT;

锁机制

MySQL使用锁来实现事务的隔离性,不同的存储引擎和隔离级别使用不同的锁策略。

锁的类型

锁类型 说明 适用场景
共享锁(S锁) 读锁,多个事务可以同时持有 SELECT语句
排他锁(X锁) 写锁,只允许一个事务持有 INSERT、UPDATE、DELETE语句
行锁 锁定单行数据 InnoDB存储引擎
表锁 锁定整个表 MyISAM存储引擎、某些DDL操作
意向锁 表级锁,表示事务将要对表中的行加锁 InnoDB存储引擎

显式加锁

-- 共享锁(读锁)
SELECT * FROM accounts WHERE id = 1 LOCK IN SHARE MODE;

-- 排他锁(写锁)
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;

-- 表级锁
LOCK TABLES accounts WRITE;
-- 操作完成后解锁
UNLOCK TABLES;

死锁

什么是死锁?

死锁是指两个或多个事务相互等待对方释放锁,导致所有事务都无法继续执行的情况。

-- 死锁示例
-- 事务A
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;  -- 锁定id=1的行

-- 事务B
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 2;  -- 锁定id=2的行

-- 事务A
UPDATE accounts SET balance = balance + 100 WHERE id = 2;  -- 等待事务B释放id=2的锁

-- 事务B
UPDATE accounts SET balance = balance + 100 WHERE id = 1;  -- 等待事务A释放id=1的锁
-- 此时发生死锁

死锁预防与解决

死锁预防策略:

事务最佳实践

事务使用最佳实践:

实战场景:转账操作

-- 完整的转账事务示例
START TRANSACTION;

-- 检查余额
SELECT balance INTO @balance FROM accounts WHERE id = 1 FOR UPDATE;
IF @balance < 100 THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '余额不足';
END IF;

-- 扣减转出账户
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

-- 增加转入账户
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

-- 记录转账日志
INSERT INTO transfer_logs (from_account, to_account, amount, transfer_time)
VALUES (1, 2, 100, NOW());

-- 提交事务
COMMIT;

-- 如果出错,自动回滚
-- ROLLBACK;

事务性能优化

性能优化策略:
  1. 合理使用隔离级别:READ COMMITTED提供较好的并发性能和数据一致性
  2. 使用索引:确保WHERE条件字段有索引,减少锁定范围
  3. 批量操作:对于大量数据操作,使用批量处理减少事务数量
  4. 连接池:使用连接池管理数据库连接,减少连接开销
  5. 监控死锁:定期检查死锁日志,优化易死锁的代码
  6. 分区表:对于大表,使用分区减少锁定范围
  7. 读写分离:将读操作分流到从库,提高并发性能
练习题:
  1. 编写一个完整的转账事务,包括余额检查、转账操作和日志记录
  2. 演示不同隔离级别下的并发问题(脏读、不可重复读、幻读)
  3. 使用保存点实现部分事务回滚
  4. 分析并解决一个死锁场景
  5. 设置不同的事务隔离级别,观察性能差异
  6. 编写一个批量插入的事务,确保数据一致性
  7. 模拟网络中断场景,测试事务的持久性
  8. 设计一个高并发下的秒杀系统,使用事务和锁保证数据一致性