事务#1对第2个事务执行WHERE
的数据集(INSERT
子句)进行操作,该事务符合第1个事务中的子句。
如果第二次提交第一次,第一次交易是否会失败?
我有下表(在PostgreSQL 9.5 db中)
CREATE TABLE public.foo (id serial PRIMARY KEY, mynum integer);
以及以下数据
id | mynum
----+-------
1 | 10
2 | 10
3 | 10
4 | 10
(4 rows)
我并行运行2个序列化事务(2 psql
个控制台):
-- both transactions
mydb=# begin;
BEGIN
mydb=# set transaction isolation level serializable;
SET
-- tx1
mydb=# select * from foo where mynum < 100;
id | mynum
----+-------
1 | 10
2 | 10
3 | 10
4 | 10
(4 rows)
--tx1: Shouldn't freeze data visible for tx1 select?
--tx2
mydb=# insert into foo (mynum) values (10);
INSERT 0 1
-- tx2 will insert next row with id 5 in foo table
-- Shouldn't insert of tx2 broke data snapshot visible for tx1?
--tx1
mydb=# update foo set mynum = 20 where id < 100;
UPDATE 4
-- Shouldn't here appear serialization fail or at least on tx1 commit?
--tx2
mydb=# commit;
COMMIT
--tx1
mydb=# commit;
COMMIT
-- tx1 Commit is OK - no any error
-- implicit tx
mydb=# select * from foo;
id | mynum
----+-------
1 | 20
2 | 20
3 | 20
4 | 20
5 | 10
(5 rows)
我想知道它为什么会这样,考虑到PostgreSQL文档
&#34;保证真正的可串行化PostgreSQL使用谓词锁定, 这意味着它保持锁定,允许它确定何时 写入会对先前从a读取的结果产生影响 并发事务,先运行它。&#34; 链接:http://www.postgresql.org/docs/current/static/transaction-iso.html
答案 0 :(得分:1)
SERIALIZABLE
保证并发事务的某些串行执行顺序会产生相同的结果,但这不一定与提交顺序相同。在您的情况下,顺序运行tx1
后跟tx2
会得到相同的结果,因此没有理由导致序列化失败。
永远不允许两个重叠的事务看到彼此的数据(MVCC系统确保SELECT
/ UPDATE
语句忽略新记录。当应该看到彼此的数据时,即当串行排序导致第二个事务看到第一个事务所写的记录时,会出现序列化失败。
这里的关键点是,只有当两个事务都读取并写入某些东西时才会发生这种情况。否则,始终可以通过将只读事务放在第一位,或者将只写事务放在最后来序列化它们。因此,您的单独插入内容永远不会与任何内容发生冲突(但如果tx2
也包含SELECT * FROM foo
,那么您将收到错误消息。)
当涉及更多交易时,事情并非如此简单。有一长串的例子here可以提供一些关于序列化异常发生的时间和地点的更多信息。