SQL可序列化事务如何工作? (SELECT / UPDATE vs INSERT冲突)

时间:2016-03-09 12:00:53

标签: sql database postgresql transactions

事务#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

1 个答案:

答案 0 :(得分:1)

SERIALIZABLE保证并发事务的某些串行执行顺序会产生相同的结果,但这不一定与提交顺序相同。在您的情况下,顺序运行tx1后跟tx2会得到相同的结果,因此没有理由导致序列化失败。

永远不允许两个重叠的事务看到彼此的数据(MVCC系统确保SELECT / UPDATE语句忽略新记录。当应该看到彼此的数据时,即当串行排序导致第二个事务看到第一个事务所写的记录时,会出现序列化失败。

这里的关键点是,只有当两个事务都读取并写入某些东西时才会发生这种情况。否则,始终可以通过将只读事务放在第一位,或者将只写事务放在最后来序列化它们。因此,您的单独插入内容永远不会与任何内容发生冲突(但如果tx2也包含SELECT * FROM foo,那么您将收到错误消息。)

当涉及更多交易时,事情并非如此简单。有一长串的例子here可以提供一些关于序列化异常发生的时间和地点的更多信息。