1.Question
当数据库中多个transactions 同时进行时,会出现问题:
1)脏读 dirty read: W-R
2)不可重读 unrepeatable read:R-W
3)重写 :W-W
总结起来,就是只要有transaction在写,并发了另一个transaction就很危险。
例子:
T1 read A,看到A=1,
T2 write A,让A从1变为2,
T1 read A,发现A竟然不为1了(不可重读),这就发生了不可重读。
2. Solution
给访问的对象(数据库,表,等等)加锁。
方式1. 二相锁2PL(2 phase lock)
在读数据前,获得S锁; 在写数据前,获得X锁 (get SL before read,get XL before write)。
如果对象已经加了锁:如果是S锁,可以获得S锁,不能获得X锁;如果是X锁,不能获得任何锁。
这样做的结果:serializable, 事务互不影响
问题:死锁
解决办法:为事务加时间戳(timestamp,决定优先级)。way1,求锁的退出(如果优先级低);way2,求锁的trans等待,有锁的trans退出(如果优先级低)
3.Improvement
问题:并发性差 (如果把锁加在整个数据库,那么A在写,没有别的事务能同时访问了)。
解决:细分锁的范围和类型 (不锁整个数据库,只锁表、记录...)。
1)层级锁 hierarchical lock,意向锁 intention lock
优点:加大并发性
缺点:锁的数量增加,计算开销增加
产生问题:幻读 phantom read (A读取若干行(设为集合X1)符合条件rule1(基于所有行),B修改集合X1外的行(未被上锁),改变了条件rule1。A的实际结果被改变,与之前的读取结果不一致)。
2)解决办法: 索引锁 index lock (限制了rule)
ps: 数据库引擎一般会有不同的 isolation level 的选择
read uncommitted
read committed no脏读
repeatable read no不可重读
serializable no幻读
选择合适的锁,保证并发性的情况下提高性能。