postgresql 中的锁定表

Aka*_*ash 5 sql postgresql

我有一个名为 as 的表'games',其中包含一个名为 as 的列'title',该列是唯一的,数据库中使用PostgreSQL

'game'我有一个用户输入表单,允许他在表中插入新的内容'games'。插入新游戏的函数会检查之前输入的'game'相同游戏是否'title'已经存在,为此,我得到count of rows, 具有相同的游戏'title'

我为此使用事务,开始时的插入函数使用BEGIN,获取行计数,如果行计数为 0,则插入新行,并且在过程完成后,它会COMMITS发生变化。

问题是,title如果用户同时提交,两个相同的游戏有可能会被插入两次,因为我只是获取要检查重复记录的行数,并且每个事务都会被插入彼此隔离

我想在获取行数时锁定表:

LOCK TABLE games IN ACCESS EXCLUSIVE MODE;
SELECT count(id) FROM games WHERE games.title = 'new_game_title' 
Run Code Online (Sandbox Code Playgroud)

这也会锁定表进行读取(这意味着另一个事务必须等待,直到当前事务成功完成)。这将解决问题,这正是我所怀疑的。有没有更好的方法来解决这个问题(避免重复使用games相同的title

mvp*_*mvp 5

在这种情况下您不需要锁定您的表。

相反,您可以使用以下方法之一:

  • UNIQUE为确实必须唯一的列定义索引。在这种情况下,第一个事务将成功,第二个事务将出错。
  • 定义AFTER INSERT OR UPDATE OR DELETE将检查您的条件的触发器,如果​​不成立,则应该RAISE出错,这将中止违规事务

在所有这些情况下,您的客户端代码应该准备好正确处理可能因执行语句而返回的失败(例如失败的事务)。

  • +1,唯一的约束是唯一明智的方法。(不过我不太喜欢触发解决方案)。 (5认同)

Phi*_*ing 3

使用最高的事务隔离(可序列化),您可以实现与实际问题类似的效果。但请注意这可能会失败ERROR: could not serialize access due to concurrent update

我不完全同意约束方法。您应该有一个约束来保护数据完整性,但依赖该约束迫使您不仅要识别发生了什么错误,还要识别哪个约束导致了错误。问题并不像一些人讨论的那样捕获错误,而是识别导致错误的原因并提供人类可读的失败原因。根据您的应用程序所使用的语言,这几乎是不可能的。例如:告诉用户“游戏标题 [foo] 已经存在”而不是“游戏必须有价格”作为单独的约束。

有一个语句可以替代两阶段方法:

INSERT INTO games ( [column1], ... )
SELECT [value1], ...
WHERE NOT EXISTS ( SELECT x FROM games as g2 WHERE games.title = g2.title );
Run Code Online (Sandbox Code Playgroud)

我想澄清这一点......这并不是唯一约束(需要额外的索引数据)的替代方案。您必须拥有一个来保护您的数据免遭损坏。