Anomalies in database
之前学习过各种异象,总是记乱,整理成文档备份
为了更好理解相关异象,做如下数据准备:
1 | CREATE TABLE accounts( |
Lost Update
当两个事务读取同一表行,然后其中一个事务更新该行,最后另一个事务更新同一行而不考虑第一个事务所做的任何更改时,就会发生丢失更新异常。
Dirty Reads
当一个事务读到了其他事务尚未尚未提交的更改时,就会发生脏读异常
Phantom Reads anomaly
当同一个事务执行两个相同的查询返回一组满足特定条件的行,而另一个事务添加一些满足该条件的其他行并在这些查询之间的时间间隔内提交更改时,就会发生幻读异常。
Read skew
假设我们要在bob的账户之间转账
Transaction1
1 | woodhead=# BEGIN; |
与此同时,另一个事务2 开始循环bob的账户计算bob的账户结余(金额)
Transaction2
1 | woodhead=# BEGIN; |
这个时候,事务1提交成功:
1 | woodhead=*# UPDATE accounts SET amount = amount + 100 WHERE id = 3; |
事务2 开始读取第二个账户(读已提交的隔离状态下会读取到已提交的数据)
1 | woodhead=*# SELECT amount FROM accounts WHERE id = 3; |
最终结果:事务2读取到了1100块钱,因为它读到了不正确的数据,这种异常叫做读偏序
Write skew
我们定义如下一致性规则:只要总余额非负,就允许客户的部分账户出现负余额。
事务1获取总额
1 | woodhead=# select * from accounts; |
事务2同样获取总额
1 | woodhead=# BEGIN ISOLATION LEVEL REPEATABLE READ; |
第一个事务合理地假设,它可以从某个账户扣除 600 元。
1 | woodhead=*# UPDATE accounts SET amount = amount - 600.00 WHERE id = 2; |
第二个事务得到同样的结论,但是从另一个账户扣除:
1 | woodhead=*# UPDATE accounts SET amount = amount - 600.00 WHERE id = 3; |
事务1也提交,然后查询:
1 | woodhead=*# commit; |
现在bob的总余额是负的,虽然每个事务单独运行都是正确的。这种异常叫写偏序