我有一个名为的表'games',其中包含一个名为的列'title',此列是唯一的,数据库用于PostgreSQL
'games'
'title'
PostgreSQL
我有一个用户输入表格,允许他'game'在'games'表格中插入新的表格。插入新游戏的功能会检查先前输入的'game'具有相同游戏的功能是否'title'已经存在,为此,我得到了count of rows具有相同游戏的'title'。
'game'
count of rows
为此,我使用事务,插入函数在开始时使用BEGIN,获取行数,如果行数为0,则插入新行,并在处理完成后COMMITS进行更改。
BEGIN
COMMITS
问题在于,title如果用户同时提交两个具有相同游戏的游戏,则有可能会被插入两次,因为我只是获得了chk重复记录的行数,并且每笔交易都会彼此 隔离
title
我想到在获取行数时 锁定表 :
LOCK TABLE games IN ACCESS EXCLUSIVE MODE; SELECT count(id) FROM games WHERE games.title = 'new_game_title'
这也将锁定表以进行读取(这意味着另一个事务将不得不等待,直到当前事务成功完成为止)。这将解决问题,这是我所怀疑的。有没有更好的方法解决此问题(避免重复games相同title)
games
使用最高的事务隔离(可序列化),您可以实现与您的实际问题类似的事情。但是请注意,这可能会失败ERROR: could not serialize access due to concurrent update
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 );
我想对此很清楚… 这不是唯一约束的替代方法 ( 唯一约束 要求索引需要额外的数据)。您必须有一个保护您的数据免遭损坏。