简体   繁体   English

选择,插入,删除时的事务隔离

[英]Transaction Isolation on select, insert, delete

What could possibly go wrong with the following transaction if executed by concurrent users in the default isolation level of READ COMMITTED? 如果由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

You could having serious performance problems from dead locks 您可能会因死锁而出现严重的性能问题

The SELECT will obtain a shared lock on a page and then the DELETE would attempt to upgrade those locks to exclusive locks. SELECT将在页面上获取共享锁,然后DELETE将尝试将这些锁升级为独占锁。

If another user was executing the same query, it might obtain shared locks on the same page at the same time another user does. 如果另一个用户正在执行相同的查询,它可能会在另一个用户同时获取同一页面上的共享锁。 Then when one tries to upgrade to an exclusive lock, it will wait for all other shared locks to be released. 然后,当一个人尝试升级到独占锁时,它将等待释放所有其他共享锁。 The other will also be waiting for all shared locks to be released. 另一个也将等待释放所有共享锁。 Both will have a shared lock and waiting for the other to release that shared lock so itself can obtain an exclusive lock. 两者都将拥有一个共享锁并等待另一个释放该共享锁,以便自己可以获得独占锁。 Other queries will pile up trying to do the same, and soon the deadlocks will begin to be detected and the queries will begin to get cancelled and rolled back. 其他查询将会尝试执行相同操作,很快就会开始检测到死锁,并且查询将开始被取消并回滚。 Depending on the frequency of the queries the dead lock detection of the DB engine may not be killing off queries as fast as new ones are coming in, meaning none of the queries will succeed. 根据查询的频率,数据库引擎的死锁检测可能不会像新的查询一样快地查询查询,这意味着任何查询都不会成功。

You would need to add something like a hint in the select to request that an exclusive lock be obtained from the get-go. 您需要在select中添加类似提示的内容,以请求从一开始就获得独占锁。 Or you could move the select outside of the transaction and use concurrency conflict detection in your other statement's where criteria. 或者您可以在事务外部移动选择,并在您的其他语句中使用并发冲突检测。

Thew whole thing is strange to me. 我觉得整件事都很奇怪。 What is the purpose of the select? 选择的目的是什么? It accomplishes nothing. 它什么都没做。 Write a delete to select the records you want. 编写删除以选择所需的记录。 What would strike me a problem of concurrent users is that they will be trying to insert the same records since you hard-coded the values and thus would probably run into the unique constraints that you probably have on tid or the tid, pid combo. 什么会让我遇到并发用户的问题是,他们会尝试插入相同的记录,因为你对值进行了硬编码,因此可能遇到你可能对tid或tid,pid组合的唯一约束。

Honestly what are you trying to accomplish here? 老实说,你想在这里完成什么? This looks like an ad hoc query that was meant for one-time usage that you are trying to run multiple times. 这看起来像是一个即席查询,用于尝试多次运行的一次性使用。 It is almost always a bad idea to hard-code like this. 像这样硬编码几乎总是一个坏主意。

You really should mention if you're using oracle or postgres. 如果你使用的是oracle或postgres,你真的应该提一下。 Also, you should explicitly specify your locking and not rely on default behavior. 此外,您应该明确指定锁定,而不是依赖默认行为。 They may change with other databases or database versions. 它们可能随其他数据库或数据库版本而变化。

You don't use a lock for the SELECT, so everybody will get the same results, everybody will see records tid 1, 3 and 5. Everybody will process these records and everybody will try to delete these records. 你没有对SELECT使用锁,所以每个人都会得到相同的结果,每个人都会看到tid 1,3和5的记录。每个人都会处理这些记录,每个人都会尝试删除这些记录。 And that's not going to work, the delete operation will place a lock. 这不会起作用,删除操作将锁定。 Only one transaction can lock these records, all other transactions have to wait for commit of the first transaction. 只有一个事务可以锁定这些记录,所有其他事务必须等待第一个事务的提交。 This transaction will insert the new records and commit, all others will delete nothing (can't find records, no problem) and insert the new records as well. 此事务将插入新记录并提交,所有其他事务将不删除任何内容(无法查找记录,没有问题)并插入新记录。 These records have the same data, is that a problem? 这些记录有相同的数据,是一个问题吗?

Maybe you want a SELECT ... FROM ... FOR UPDATE; 也许你想要一个SELECT ... FROM ... FOR UPDATE; to lock the records you want to process. 锁定要处理的记录。 http://www.postgresql.org/docs/8.4/interactive/sql-select.html http://www.postgresql.org/docs/8.4/interactive/sql-select.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM