gpt4 book ai didi

sql - 更新语句是否不受竞争条件的影响?

转载 作者:行者123 更新时间:2023-12-04 22:07:15 25 4
gpt4 key购买 nike

我想确保电子邮件只发送一次,因此我在 Oracle SQL 中使用以下语句:

update mytable set mail_sent = 't' where id = ? and mail_sent = 'f'

并检查修改的行数。如果没有修改任何行,则另一个进程首先执行相同的操作并发送邮件。如果修改了 1 行,我发送邮件。 (当然,如果发送邮件失败,我会重置 mail_sent。进程崩溃并将 mail_sent 留在 't' 的可能性很小,所以没有邮件发送。我会接受它。)

我不能完全说服自己这对于竞争条件是安全的(进程 1 在进程 1 写入“t”之前读取“f”,进程 2 读取“f”,因此两个进程都认为它们修改了行并发送了 2 封电子邮件。我将隔离级别设置为 SERIALIZABLE 以避免出现问题,但这实际上是必要的,还是没有它我安全吗?

最佳答案

有一组 Tom Kyte 关于并发更新期间发生的事情的优秀文章,值得一读:

  • http://tkyte.blogspot.ru/2005/08/something-different-part-i-of-iii.html
  • http://tkyte.blogspot.ru/2005/08/part-ii-seeing-restart.html
  • http://tkyte.blogspot.ru/2005/09/part-iii-why-is-restart-important-to.html

  • 长话短说,如果两个语句同时进行更新,则后一个:
  • 执行一致读取(语句开始时的行版本)
  • 检查该行是否符合更新
  • 的 where 条件
  • 如果是,它会读取当前模式 - 获取该行的最新提交版本 - 并检查它是否仍然与步骤 1(!)中的行相同,因此我们不会更新我们不打算更新的内容
  • 如果不是,则该行不会更新,整个更新语句会重新启动,但这是另一回事。

  • 因此,如果您的第一次更新提交“t”,则第二次更新将永远不会再次更新该行。您可以使用 sql%rowcount 进行检查。

    一个简单的测试用例(36 和 37 是这里的两个并发 session ):
    -- first session updates, locks the row
    00:41:44 LKU@sandbox(36)> update mail set mail_sent = 't' where id = 1 and mail_sent = 'f';

    1 row updated.

    Elapsed: 00:00:00.21

    -- second session tries to update the same row, it hangs as the row is locked
    00:58:13 LKU@sandbox(37)> update mail set mail_sent = 't' where id = 1 and mail_sent = 'f';

    -- first session commits
    00:58:27 LKU@sandbox(36)> commit;

    Commit complete.

    Elapsed: 00:00:00.00

    -- no rows updated in second!
    00:58:13 LKU@sandbox(37)> update mail set mail_sent = 't' where id = 1 and mail_sent = 'f';

    0 rows updated.

    Elapsed: 00:00:33.12 -- time of me switching between sqlplus tabs and copy-pasting text here ;)

    因此,我可以得出结论,如果您在执行更新后检查 session 更新的行数 - 您是安全的。

    关于sql - 更新语句是否不受竞争条件的影响?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18768467/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com