其他用户能否闯入我的 sql 操作序列?

Can other users break into my sql sequence of operations?

我向数据库 (Postgres) 执行插入操作,然后立即获取最后一个序列号。如果10个人做同样的事情,他们能打乱我数据库操作的顺序吗?

INSERT INTO table VALUES (DEFAULT,...);
SELECT currval(pg_get_serial_sequence('table','column')) as inserted_id;

恐怕会发生这样的情况:

INSERT INTO table VALUES (DEFAULT,...);
Meanwhile, another user was doing insertions and I end up getting the wrong id;
SELECT currval(pg_get_serial_sequence('table','column')) as inserted_id;

pg_get_serial_sequence(table_name, column_name) 获取 serialsmallserialbigserial 列使用的序列的名称。

来自 the PostgreSQL documentation currval 将:

Return the value most recently obtained by nextval for this sequence in the current session. (An error is reported if nextval has never been called for this sequence in this session.) Because this is returning a session-local value, it gives a predictable answer whether or not other sessions have executed nextval since the current session did.

综合以上,注意重点,回答你的问题"If 10 people do the same thing, can they break the sequence of my database operations?"是否定的

这也很容易测试。使用 pgAdmin 的两个实例或您喜欢的任何客户端。

在客户端 1 上:

CREATE TABLE foo (id BIGSERIAL PRIMARY KEY, some_column TEXT);
INSERT INTO foo(some_column) VALUES('a');

在客户端 2 上:

INSERT INTO foo(some_column) VALUES('b');

在客户端 1 上:

SELECT CURRVAL(PG_GET_SERIAL_SEQUENCE('foo','id')) AS inserted_id; -- it will return 1

在客户端 2 上:

SELECT CURRVAL(PG_GET_SERIAL_SEQUENCE('foo','id')) AS inserted_id; -- it will return 2

即使是并发写访问也是安全的,比如非常好。

除非您有多个列默认值从序列中获取数字(通常只是 serial 类型的列),否则使用更通用的 lastval() 甚至更安全 - 而且更便宜,因为您不需要使用 pg_get_serial_sequence() 的额外函数调用。 Per documentation:

Return value most recently obtained with nextval for any sequence

您也不能让触发器导致额外的序列操作 - 但这可能会使 currval() 的使用也不可靠。

更好的选择

INSERT INTO table(col1, col2, ...)  -- target list!statements
VALUES ('val1', 'val2', ...)        -- don't mention serial columns at all
RETURNING table_id;                 -- name(s) of auto-generated column(s)
  • 这种形式比使用 lastval()currval() 更短、更便宜,甚至更安全。它甚至可以安全地防止在同一序列上多次调用 nextval()(不太可能,但可能是由触发器、规则或函数的副作用引起的)以及可能影响标识符解析方式的 search_path 的更改。在对服务器的一次调用中,您获得了为该列插入的 实际值

  • 几乎总是 为持久的INSERT 语句添加目标列表更好。如果您稍后更改 table 布局,这样的语句不太可能被破坏(以危险的方式)。

  • 完全省略 INSERT 中应使用列默认值填充的列。

更多详情:

  • PostgreSQL next value of the sequences?

  • Reference value of serial column in another column during same INSERT

如果你打算在另一个INSERT中使用新ID(这是典型的用例),我建议data-modifying CTE:

  • PostgreSQL multi INSERT...RETURNING with multiple columns