如果由READ COMMITTED的默认隔离级别的并发用户执行,则以下事务可能出现什么问题?
BEGIN TRANSACTION
SELECT * FROM t WHERE pid = 10 and r between 40 and 60
-- ... this returns tid = 1, 3, 5
-- ... process returned data ...
DELETE FROM t WHERE tid in (1, 3, 5)
INSERT INTO t (tid, pid, r) VALUES (77, 10, 35)
INSERT INTO t (tid, pid, r) VALUES (78, 10, 37)
INSERT INTO t (tid, pid, r) VALUES (79, 10, 39)
COMMIT
答案 0 :(得分:3)
你可能会因死锁而出现严重的性能问题
SELECT将在页面上获取共享锁,然后DELETE将尝试将这些锁升级为独占锁。
如果另一个用户正在执行相同的查询,它可能会在另一个用户同时获取同一页面上的共享锁。然后,当一个人尝试升级到独占锁时,它将等待释放所有其他共享锁。另一个也将等待释放所有共享锁。两者都将拥有一个共享锁并等待另一个释放该共享锁,以便自己可以获得独占锁。其他查询将会尝试执行相同操作,很快就会开始检测到死锁,并且查询将开始被取消并回滚。根据查询的频率,数据库引擎的死锁检测可能不会像新的查询一样快地查询,这意味着没有任何查询会成功。
您需要在select中添加类似提示的内容,以请求从一开始就获取独占锁。或者您可以在事务外部移动选择,并在您的其他语句中使用并发冲突检测。
答案 1 :(得分:1)
对我来说,整件事情都很奇怪。选择的目的是什么?它什么都没做。编写删除以选择所需的记录。什么会让我遇到并发用户的问题是,他们会尝试插入相同的记录,因为你对值进行了硬编码,因此可能会遇到你可能对tid或tid,pid组合的唯一约束。
老实说,你想在这里完成什么?这看起来像是一个即席查询,用于尝试多次运行的一次性使用。像这样硬编码几乎总是一个坏主意。
答案 2 :(得分:0)
你真的应该提一下你是否正在使用oracle或postgres。 此外,您应该明确指定锁定,而不是依赖默认行为。 它们可能会随其他数据库或数据库版本而改变。
答案 3 :(得分:0)
你没有对SELECT使用锁,所以每个人都会得到相同的结果,每个人都会看到tid 1,3和5的记录。每个人都会处理这些记录,每个人都会尝试删除这些记录。这不会起作用,删除操作将锁定。只有一个事务可以锁定这些记录,所有其他事务必须等待第一个事务的提交。此事务将插入新记录并提交,所有其他事务将不删除任何内容(无法查找记录,没有问题)并插入新记录。这些记录有相同的数据,是一个问题吗?
也许您希望SELECT ... FROM ... FOR UPDATE;
锁定您要处理的记录。
http://www.postgresql.org/docs/8.4/interactive/sql-select.html