【问题标题】:Can other users break into my sql sequence of operations?其他用户可以闯入我的sql操作序列吗?
【发布时间】:2015-04-15 17:04:24
【问题描述】:

我在数据库(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;

【问题讨论】:

  • 不,最后一个插入 ID 是每个客户端的 - 每个用户总是会得到最后一个插入查询的结果他们执行的。

标签: sql postgresql concurrency auto-increment sql-insert


【解决方案1】:

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

来自the PostgreSQL documentationcurrval 将:

返回由 nextval 为这个序列最近获得的值 在当前会话中。 (如果 nextval 从未 在这个会话中被调用这个序列。)因为这是 返回一个会话本地值,它给出一个可预测的答案是否 或者自当前会话以来没有其他会话执行过 nextval 做了

基于以上内容,注意重点,回答您的问题“如果 10 个人做同样的事情,他们会破坏我的数据库操作顺序吗?”没有。

它也很容易测试。使用两个 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

【讨论】:

    【解决方案2】:

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

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

    返回最近使用nextval 获得的任何序列的值

    您也不能有触发器导致额外的序列操作 - 但这也可能使 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 语句添加目标列表几乎总是更好。如果您稍后更改表格布局,这样的语句就不太可能中断(以危险的方式)。

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

    更多细节:

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

    【讨论】:

      猜你喜欢
      • 2017-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多