在PostgreSQL数据库中生成序列号 - 并发&隔离级别

时间:2014-06-05 14:19:46

标签: sql database postgresql concurrency isolation-level

类似的问题; Update SQL with consecutive numbering

我希望能够通过在名为num的表中递增列SeqNum来生成序列号。 SeqNum表格布局;

|num|
|===|
| 0 |

正在运行的查询;

BEGIN TRANSACTION
UPDATE SeqNum
SET num = num + 1
SELECT num from SeqNum
COMMIT TRANSACTION

我的问题是,如果我有多个进程同时运行此查询并具有READ COMMITTED隔离级别,那么select子句是否总是返回唯一的更新值。我假设这将是一致的,没有两个进程会返回相同的数字......显然这一切都在一个事务中运行。如果它不在事务中,我希望它可能返回重复值。

我不确定行为如何变化(如果有的话)取决于隔离级别。

1 个答案:

答案 0 :(得分:2)

  

在PostgreSQL中,您可以请求四种标准事务隔离级别中的任何一种。但在内部,只有三个不同的隔离级别,对应于Read Committed,Repeatable Read和Serializable等级。当您选择级别Read Uncommitted时,您真正获得Read Committed ...1

读取已提交隔离级别每个标准都无法进行脏读,这意味着这些事务无法读取并发未提交事务所写入的数据。 只能在每个标准的读取未提交的隔离级别中发生(但不会发生在PostgreSQL中:四个隔离级别仅定义哪些现象不得发生,他们没有定义哪些现象必须发生)。

简而言之,您的select子句不会始终返回唯一值。如果你把它重写为UPDATE ... RETUNRING ...,也不会,但时间窗口会非常小,所以多个事务返回相同值的可能性会低得多。

但幸运的是,PostgreSQL中唯一不受交易影响的是sequence

  

为了避免阻塞从同一序列获取数字的并发事务,永远不会回滚nextval操作;也就是说,一旦获取了一个值,它就被认为是使用的,即使稍后执行nextval的事务也会中止。这意味着中止的事务可能会在指定值的序列中留下未使用的“漏洞”。 2

     

由于序列是非事务性的,因此如果事务回滚,则setval所做的更改不会被撤消。 2