并发控制
并发控制的核心目标
在多个事务同时访问数据库时,确保数据的一致性(Consistency)和事务的隔离性(Isolation)
- 丢失更新(Lost Update):两个事务同时修改同一数据,后提交的覆盖了先提交的结果。
- 脏读(Dirty Read):事务读取到其他未提交事务的中间数据。
- 不可重复读(Non-repeatable Read):同一事务内多次读取同一数据结果不同。
- 幻读(Phantom Read):同一事务内多次查询返回的行数不同(因其他事务插入/删除了数据)。
并发控制
通过锁协调事务对数据的访问,分为两类:
- 共享锁(Shared Lock, S-Lock)
- 事务读取数据时加锁,允许其他事务加共享锁,但禁止加排他锁。
- 示例:
SELECT * FROM table WHERE ... LOCK IN SHARE MODE;
- 排他锁(Exclusive Lock, X-Lock)
- 事务修改数据时加锁,禁止其他事务加任何锁。
- 示例:
SELECT * FROM table WHERE ... FOR UPDATE;
锁的粒度:
- 行级锁(Row-level Lock):锁定单行(如InnoDB)。
- 表级锁(Table-level Lock):锁定整表(如MyISAM)。
两阶段锁协议(2PL, Two-Phase Locking)
- 扩展阶段:事务可以不断加锁,但不能释放锁。
- 收缩阶段:事务只能释放锁,不能再加锁。
- 确保可串行化,但可能导致死锁。
时间戳排序(Timestamp Ordering)
基本思想:为每个事务分配唯一时间戳,按时间戳顺序处理冲突操作。
规则:
若事务A要读取数据,必须保证该数据的最新写入时间戳 ≤ 事务A的时间戳。
若事务A要写入数据,必须保证该数据的最后读取时间戳 ≤ 事务A的时间戳,且最后写入时间戳 ≤ 事务A的时间戳。
优点:避免死锁;缺点:可能因冲突导致事务回滚。
事务隔离级别
数据库通过不同的隔离级别平衡并发性能和数据一致性。常见的隔离级别(由低到高):
读未提交(Read Uncommitted)
允许脏读、不可重复读、幻读。
读已提交(Read Committed)
禁止脏读,但允许不可重复读和幻读(多数数据库的默认级别)。
可重复读(Repeatable Read)
禁止脏读和不可重复读,允许幻读(MySQL InnoDB默认级别,通过MVCC消除幻读)。
串行化(Serializable)
完全禁止并发问题,但性能最低。