Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/74.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
postgresql中的锁表_Sql_Postgresql - Fatal编程技术网

postgresql中的锁表

postgresql中的锁表,sql,postgresql,Sql,Postgresql,我有一个名为'games'的表,其中包含一个名为'title'的列,该列是唯一的,数据库用于PostgreSQL 我有一个用户输入表单,允许他在'games'表中插入一个新的'games'。插入新游戏的函数检查以前输入的具有相同'title'的'game'是否已经存在,为此,我获得具有相同游戏'title'的行数 为此,我使用事务,开始时的insert函数使用BEGIN,获取行数,如果行数为0,则插入新行,并在流程完成后提交更改 问题是,如果用户同时提交的话,有可能会插入两个具有相同标题的游戏,

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

我有一个用户输入表单,允许他在
'games'
表中插入一个新的
'games'
。插入新游戏的函数检查以前输入的具有相同
'title'
'game'
是否已经存在,为此,我获得具有相同游戏
'title'
行数

为此,我使用事务,开始时的insert函数使用
BEGIN
,获取行数,如果行数为0,则插入新行,并在流程完成后提交更改

问题是,如果用户同时提交的话,有可能会插入两个具有相同
标题的游戏,因为我只获得了chk中重复记录的行数,并且每个事务都会彼此隔离

当获得行计数时,我想到了将表锁定为:

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

这也会锁定表进行读取(这意味着其他事务必须等待,直到当前事务成功完成)。这将解决问题,这正是我所怀疑的。是否有更好的解决方法(避免重复的
游戏
和相同的
标题

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

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

  • 为确实必须唯一的列定义
    UNIQUE
    索引。在这种情况下,第一个事务将成功,第二个事务将出错
  • 在INSERT或UPDATE或DELETE后定义
    触发器,该触发器将检查您的条件,如果它不起作用,则应
    引发
    错误,这将中止有问题的事务
在所有这些情况下,您的客户机代码都应该准备好正确处理可能通过执行语句返回的故障(如失败的事务)。

使用(可序列化)可以实现与实际问题类似的功能。但请注意,这可能会失败
错误:由于并发更新而无法序列化访问

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

您的两阶段方法有一个单独的替代方案:

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

我想澄清一下这不是唯一约束的替代方法(这需要索引的额外数据)。您必须有一个保护数据不受损坏的约束。

尝试更改事务的隔离级别。为什么不使用唯一约束,而不是自己尝试对抗竞争条件?@muistooshort我可以这样做,但它会在用户端产生错误,然后自己捕获错误。您正试图使用一堆脆弱的乱码来避免一点简单的错误处理,为自己节省一些麻烦,让数据库管理数据及其约束。无论如何,您必须捕获错误。除了违反约束之外,还有很多因素会导致插入失败:内存错误、连接问题、权限等。也要抓住这一点。+1,唯一的约束是唯一可行的方法。(虽然我不太喜欢触发器解决方案)。使用类似于
从games WHERE.title='new\u game\u title'更新的游戏中选择count(id)这样的Thinkg如何?阿卡什:你不能计数也不能锁定更新,这是另一个进程尚未提交的内容。正如其他人提到的,唯一的约束是唯一安全的解决方案。这个问题有一个唯一的约束,所以请使用它。@Akash:不要使用显式锁定。使用唯一约束并捕获错误。这样,您的应用程序将具有更高的可伸缩性,并且在DB服务器上使用更少的资源。正如其他人所指出的,您无论如何都必须实现错误处理。“我计划使用唯一约束进行更新”为什么?这会使您的应用程序运行缓慢,而且FOR更新根本不会添加任何内容。“几乎不可能抓住正确的错误”为什么?只要阅读(捕捉)错误消息,您就完成了。实施起来非常简单,我认为这是错误的;由于比赛条件,它将允许多个插入单个游戏标题,因为插入发生在内部SELECT找到零行时,因此没有锁定。我理解,具有唯一约束将阻止多个相同标题插入,但插入..选择不存在的地方提出的解决方案具有竞争条件;有可能它会插入一个重复的标题,而调用者也不会知道,所以我看不到它的价值?您说“不管约束如何,都会可靠地插入行”,但事实并非如此,因为同一标题的两个并发插入可能都会成功。可能在我最初编写这篇文章时,我做了太多的Oracle编码。但我注意到手册中关于“读取承诺隔离级别”的描述在
8.3
8.4
之间发生了变化。如果不挖掘出一个过时的博士后版本,我就无法判断这个建议是否总是错误的,或者只是过时了。我把我的答案改成了正确答案。我仍然不确定它是否正确,但在这个问题上你可能比我知道得多。我觉得这些东西很有趣