【问题标题】:Transaction Isolation on select, insert, delete选择、插入、删除时的事务隔离
【发布时间】:2011-02-04 14:08:22
【问题描述】:

如果并发用户在默认隔离级别 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

【问题讨论】:

    标签: database oracle postgresql isolation acid


    【解决方案1】:

    死锁可能会导致严重的性能问题

    SELECT 将获得一个页面上的共享锁,然后 DELETE 将尝试将这些锁升级为独占锁。

    如果另一个用户正在执行相同的查询,它可能会在另一个用户同时获得同一页面上的共享锁。然后当尝试升级到独占锁时,它将等待所有其他共享锁被释放。另一个也将等待所有共享锁被释放。两者都将拥有一个共享锁,并等待对方释放该共享锁,以便自己获得排他锁。其他查询会堆积起来尝试做同样的事情,很快就会开始检测到死锁,并且查询将开始被取消和回滚。根据查询的频率,数据库引擎的死锁检测可能不会像新的查询一样快地杀死查询,这意味着没有一个查询会成功。

    您需要在选择中添加类似提示的内容,以请求从一开始就获得排他锁。或者,您可以将 select 移到事务之外,并在其他语句的 where 条件中使用并发冲突检测。

    【讨论】:

      【解决方案2】:

      整个事情对我来说都很奇怪。选择的目的是什么?它一事无成。编写删除以选择所需的记录。并发用户的问题是他们将尝试插入相同的记录,因为您对值进行了硬编码,因此可能会遇到您可能对 tid 或 tid、pid 组合具有的唯一约束。

      老实说,你想在这里完成什么?这看起来像是一个临时查询,旨在用于您尝试多次运行的一次性使用。像这样硬编码几乎总是一个坏主意。

      【讨论】:

      • 之所以存在选择,是因为插入语句(并非真正像那样硬编码)依赖于从选择返回的数据。这是发生了什么:我有一个包含 tid、product_id、start_date、end_date 和 discount 的表。当用户插入产品的日期范围和折扣时,我选择所有重叠的日期,删除它们,然后根据依赖于重叠选择中返回的记录的某种算法插入新记录。我只是想防止使用 INSERT AFTER 触发器在数据库中发生重叠。
      【解决方案3】:

      您确实应该提及您使用的是 oracle 还是 postgres。 此外,您应该明确指定您的锁定,而不是依赖默认行为。 它们可能会随着其他数据库或数据库版本而改变。

      【讨论】:

        【解决方案4】:

        您没有为 SELECT 使用锁,所以每个人都会得到相同的结果,每个人都会看到 tid 1、3 和 5 的记录。每个人都会处理这些记录,每个人都会尝试删除这些记录。那是行不通的,删除操作会加锁。只有一个事务可以锁定这些记录,所有其他事务必须等待第一个事务的提交。该事务将插入新记录并提交,所有其他事务将不删除任何内容(找不到记录,没问题)并插入新记录。这些记录有相同的数据,有问题吗?

        也许您想要一个SELECT ... FROM ... FOR UPDATE; 来锁定您要处理的记录。 http://www.postgresql.org/docs/8.4/interactive/sql-select.html

        【讨论】:

        • INSERT INTO 语句是插入内容的示例。它们将是动态的,取决于 tid 和 pid——与删除相同。基本上,如果另一个事务碰巧同时在同一个 tid 和 pid 上运行,我希望一切都失败。所以,我想我想在选择时“锁定”,但只在 pid = 10 的行上,这样没有其他事务将同时删除或插入此条件的数据。我只是不明白锁定。我的读取次数多,写入次数少。如果可能。我不希望读取因为插入而挂起或失败。
        • 我的意思是,我不会因为此类事务正在运行而使这些事务之外的正常选择语句失败。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-12-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-13
        • 1970-01-01
        相关资源
        最近更新 更多