事务与并发控制
理解事务 ACID 特性
掌握事务的使用方法
了解隔离级别与并发问题
核心讲解
(1)事务 Transaction
一组 SQL 操作,要么全部成功,要么全部失败,保证原子性。
四大特性 ACID:
原子性(Atomicity):不可分割,全成全败
一致性(Consistency):事务前后数据保持一致
隔离性(Isolation):多个事务互不干扰
持久性(Durability):提交后永久保存
(2)事务控制
开始:
BEGIN;或者START TRANSACTION;提交:
COMMIT;回滚:
ROLLBACK;保存点:
SAVEPOINT 名称;,可以部分回滚
(3)并发问题
多个事务同时操作数据,会出现:
脏读:读到未提交的数据
不可重复读:同一事务两次读不一样
幻读:同一事务两次查询行数不一样
(4)隔离级别
表格
隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
读未提交 | 可能 | 可能 | 可能 |
读已提交 | ❌ | 可能 | 可能 |
可重复读 | ❌ | ❌ | 可能 |
串行化 | ❌ | ❌ | ❌ |
PG 默认隔离级别是读已提交,通过 MVCC 实现,并发性能好。
代码示例
-- ===== 基础事务 =====
BEGIN; -- 开启事务
INSERT INTO student(name, class_id) VALUES ('事务测试1', 1);
INSERT INTO student(name, class_id) VALUES ('事务测试2', 1);
-- 提交,全部生效
COMMIT;
-- ===== 回滚示例 =====
BEGIN;
INSERT INTO student(name, class_id) VALUES ('回滚测试', 1);
SELECT * FROM student WHERE name = '回滚测试'; -- 能看到
ROLLBACK; -- 回滚,都没了
SELECT * FROM student WHERE name = '回滚测试'; -- 看不到了
-- ===== 保存点 =====
BEGIN;
INSERT INTO student(name, class_id) VALUES ('A', 1);
SAVEPOINT sp1;
INSERT INTO student(name, class_id) VALUES ('B', 1);
-- 回滚到保存点sp1,B的插入撤销,A还在
ROLLBACK TO sp1;
COMMIT;
-- ===== 隔离级别 =====
-- 设置隔离级别
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
-- ... 事务操作
COMMIT;
常见误区
自动提交事务:默认每条 SQL 都是自动提交的事务,显式 BEGIN 才是手动事务
事务里放太久:长事务会导致锁、日志膨胀,尽量短小
隔离级别越高越好:级别越高性能越差,根据业务选择,默认读已提交大多数场景够用
课后练习
编写一个转账事务:A 账户减钱,B 账户加钱
测试回滚操作,验证数据回滚
了解四个隔离级别的区别
思考:什么场景下需要高隔离级别?

