我有一张包含证书编号的表格。每个证书由一个系列字母和一个序列号组成。证书必须是唯一的并且不允许有间隙,即如果存在 A-1234,那么 A-1233 也必须存在。每个系列都有自己的系列,即A-1234和B-1234可以愉快地共存。
保存信息的表是这样的:
CREATE TABLE "Certificate"
(
id serial NOT NULL,
series character(1) NOT NULL,
serial integer NOT NULL,
CONSTRAINT "Certificate_pkey" PRIMARY KEY (id ),
CONSTRAINT "Certificate_series_serial_key" UNIQUE (series , serial )
)
WITH (
OIDS=FALSE
);
现在的问题是如何在给定特定系列的情况下创建下一个序列号。Postgres 序列似乎不是要走的路,因为如果插入因任何原因失败或者如果需要来自序列的新值的事务被回滚,这些将产生间隙。
我的想法如下:
#! /usr/bin/env python3.2
import postgresql.driver.dbapi20 as pgdb
credentials = #my db credentials
SERIES = 'B'
dbcon = pgdb.connect (**credentials)
cursor = dbcon.cursor ()
cursor.execute ('''insert into "Certificate" ("series", "serial")
(select %s, coalesce (max ("serial"), 0) + 1
from "Certificate"
where "series" = %s) ''', [SERIES] * 2)
input () #just to keep the transaction open some time
cursor.close ()
dbcon.commit ()
dbcon.close ()
不幸的是,这不是线程安全的。如果我在两个 shell(比如 A 和 B)上启动此脚本两次,则会发生以下情况:
- 我在 shell A 上启动脚本,它保存在事务中
input ()
。 - 我在 shell B 上启动脚本,它保存在事务中
input ()
。 - 我在 shell A 上按 enter 并提交事务。
- 在这个精确的时刻,shell B 抛出一个 (expected)
postgresql.exceptions.UniqueError: duplicate key value violates unique constraint "Certificate_series_serial_key"
。
如何根据给定的系列字母以线程安全的方式将下一个证书插入此表中?