两个规则在这个问题中发挥作用:
让我们列举语句:
爱丽丝
A1:从 R 中选择 SUM(x);
A2:提交;
贝蒂
B1:插入 R 值(10);
B2:插入 R 值(20);
B3:插入 R 值(30);
B4:提交;
颂歌
C1:从 R 中删除 x=30;
C2:从 R 中删除 x=20;
C3:提交;
对于每个值a)1040 b)950 c)1030 d)1080,您想找出这些语句的执行顺序是否使得在A1 步骤中的SELECT SUM(x) FROM R 恰好产生该值,给定上述事务规则。
a=1040
1040 可以用这个执行顺序(以及其他)读取:
B1
B2
C1 -- DELETE WHERE x=30 什么都不做,因为 x=30 在 R 中不存在。
B3
B4 - 现在 A1 在 R 中会看到 10,20,30,所以此时 SUM(x) 为 1060
C2 -- DELETE WHERE x=20 确实删除了存在且对 C 可见的 x=20
C3 -- 提交删除 x=20
A1 -- 现在 A1 可以看到 10,30 所以 SUM(x)=1040
A2 -- 提交(无效,A 只读取)
编辑:有些人不相信这个结果是可能的,所以请在问题底部查看从 postgres 会话粘贴的实际演示副本。
b=950
值20,30一开始不在表中,所以如果C1和C2可以去掉30和20,那是因为B2和B3加了它们,如果这样做了,B1先加了10,所以结果至少是 960。
在 C1 和 C2 因尚未写入而无法删除 30 或 20 的情况下,结果 SUM(x) 必然大于 960。
所以 A1 永远看不到 SUM(x) 小到 950,这是不可能的。
c=1030
要让 A1 读取 1030,它必须在表中看到两行 (10)、(20) 或一行 (30),不包括其他任何内容,因为其他组合的总和不等于 30。
由于原子性,由 B1,B2,B3 插入的 (10,20,30) 行将同时变为可见。 C1 和 C2 可以分别撤消 B3 和 B2 的作用,但是如果 C1 找到并删除 x=30,那么 C2 也必然会找到并删除 x=20。
A1 在 C3 运行之前看不到 C1 的结果,如果 C3 已经运行,C2 也有,所以 30 和 20 都从 A 的可见性中消失了,所以它只看到 (10),而不是 (10),(20) .
单独看到 (30) 也是不可能的,因为如果 (30) 存在,那么 (10) 也会存在,
因为 x=10 是由 B1 插入的,之后就再也没有删除过。
所以 A1 永远看不到 SUM(x)=1030。
d=1080
1000+10+20+30 = 1060 且代码不再添加任何行,因此无论执行顺序如何,都不可能超过 1060。
编辑:
postgresql 9.5 的实际演示
# 在里面
$ psql -d 测试
test=# 创建表 R(x int);
创建表
test=# 插入 R 值(1000);
插入 0 1
测试=# 显示事务隔离;
交易隔离
----------------------
读已提交
(1 行)
测试=# \q
** 启动 3 个不同的并发会话 A、B、C,并使用不同的提示进行区分:
$ psql -d 测试
\set PROMPT1 '爱丽丝%R%# '
爱丽丝=#
$ psql -d 测试
\set PROMPT1 '贝蒂%R%# '
贝蒂=#
$ psql -d 测试
\set PROMPT1 'carol%R%#'
卡罗尔=#
现在让我们按照上面提到的顺序运行命令,哪个会话做什么由提示显而易见。
爱丽丝=#开始;
开始
贝蒂=#开始;
开始
卡罗尔=#开始;
开始
betty=# 插入 R 值(10);
插入 0 1
贝蒂=#插入R值(20);
插入 0 1
carol=# 从 R 中删除 x=30;
删除 0
贝蒂=#插入R值(30);
插入 0 1
贝蒂=#提交;
犯罪
carol=# 从 R 中删除 x=20;
删除 1
卡罗尔=#提交;
犯罪
alice=# 从 r 中选择 sum(x);
和
------
1040
(1 行)
爱丽丝=#提交;
犯罪