技能点总结
技能点总结
- 1、多线程导致事物失效的原因
- 1.1 线程间竞争条件
- 1.2 可见性问题
- 1.3 原子性破坏
- 1.4 死锁与活锁
- 1.5 事务隔离级别问题
- 1.5.1 脏读、不可重复读、幻读
1、多线程导致事物失效的原因
多线程环境下事物失效是一个常见问题,主要原因包括以下几个方面:
1.1 线程间竞争条件
共享资源冲突:多个线程同时访问和修改共享数据,导致数据不一致
竞态条件:线程执行顺序影响最终结果,导致不可预测的行为
1.2 可见性问题
CPU缓存不一致:线程可能读取的是本地缓存而非最新内存值
指令重排序:编译器和处理器优化可能导致指令执行顺序改变
1.3 原子性破坏
非原子操作被中断:看似单一的操作可能被线程切换打断
复合操作非原子:多个操作组合在一起时缺乏整体原子性
1.4 死锁与活锁
资源互斥:线程相互等待对方释放锁
活锁:线程不断重试但无法取得进展
1.5 事务隔离级别问题
脏读、不可重复读、幻读:不同隔离级别下可能出现的问题
事务传播行为不当:嵌套事务处理不当导致部分失效
1.5.1 脏读、不可重复读、幻读
1. 脏读 (Dirty Read)
定义:一个事务读取了另一个未提交事务修改过的数据。
示例:
-- 事务A
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1; -- 未提交-- 事务B
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- 读取了未提交的修改
COMMIT;-- 事务A
ROLLBACK; -- 撤销之前的修改
特点:
- 读取了可能不存在的数据(因为事务可能回滚)
- 发生在读未提交(Read Uncommitted)隔离级别
- 最严重的并发问题,可能导致业务逻辑错误
2. 不可重复读 (Non-repeatable Read)
定义:在同一事务内,多次读取同一数据返回不同结果(因为其他事务修改了该数据并提交)。
示例:
-- 事务A
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- 第一次读取,返回1000-- 事务B
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT; -- 提交修改-- 事务A
SELECT balance FROM accounts WHERE id = 1; -- 第二次读取,返回900
COMMIT;
特点:
- 同一事务内相同查询返回不同结果
- 发生在读已提交(Read Committed)隔离级别
- 由数据修改引起(UPDATE操作)
3. 幻读 (Phantom Read)
定义:在同一事务内,多次执行同一查询返回不同的行集合(因为其他事务插入了新数据并提交)。
示例:
-- 事务A
BEGIN;
SELECT * FROM accounts WHERE balance > 1000; -- 返回2条记录-- 事务B
BEGIN;
INSERT INTO accounts(id, balance) VALUES (3, 2000);
COMMIT; -- 提交新记录-- 事务A
SELECT * FROM accounts WHERE balance > 1000; -- 返回3条记录
COMMIT;
特点:
- 同一事务内相同范围查询返回不同行数
- 发生在可重复读(Repeatable Read)隔离级别
- 由数据插入或删除引起(INSERT/DELETE操作)
隔离级别与问题对照表
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Read Uncommitted(读未提交) | 可能 | 可能 | 可能 |
Read Committed(读提交) | 避免 | 可能 | 可能 |
Repeatable Read(重复读) | 避免 | 避免 | 可能 |
Serializable | 避免 | 避免 | 避免 |