【问题标题】:How do transactions work in the context of reads to the database?事务在读取数据库的上下文中如何工作?
【发布时间】:2016-03-02 00:21:13
【问题描述】:

我正在使用事务来更改 SQL 数据库。据我了解,这意味着对数据库的更改将以全有或全无的方式发生。我想知道的是,这对读取有任何保证吗?例如,假设我有一些像这样的(伪)代码:

1) start TRANSACTION
2) INSERT INTO users ... // insert some data
3) count = SELECT COUNT(*) FROM ... // count something in the database
4) if count > 10: // do something based on the read
5)     INSERT INTO other_table ... // write based on the read
6) COMMMIT TRANSACTION

在这段代码中,我正在执行INSERT,然后是SELECT,然后根据SELECT 的结果有条件地执行另一个INSERT

所以我的问题是,如果另一个进程在步骤 (3) 和 (5) 之间修改数据库,count 变量和我的事务会发生什么情况?

如果有什么不同,我正在使用 PostgreSQL。

【问题讨论】:

    标签: postgresql acid


    【解决方案1】:

    正如鑫所指出的,这取决于isolation level

    在默认的READ COMMITTED 级别,来自其他会话的记录在提交时将变得可见;如果您根本没有启动事务,您将看到相同的记录(当然,其他进程会看到您的插入出现在不同的时间)。

    使用REPEATABLE READ,您的查询将不会在您的事务开始后看到其他会话提交的任何记录。但是,虽然您不必担心SELECT COUNT(*) 在事务期间更改的结果,但您不能假设在您提交时该结果仍然准确。

    使用SERIALIZABLE 提供了最有力的保证:如果您的脚本在获得对数据库的独占访问权时执行正确的操作,那么它会在存在其他可序列化事务的情况下执行正确的操作(否则它将彻底失败)。但是,这意味着所有可能干扰您的事务都必须使用相同的隔离级别(这是有代价的),并且所有事务都必须准备好在序列化失败的情况下重试其事务。

    当可序列化事务不是一个选项时,您通常会通过显式锁定并发写入来防止竞争条件。锁定选择的记录通常就足够了,但您不能完全锁定COUNT(*) 的结果;在你的情况下,你可能需要lock the whole table

    【讨论】:

      【解决方案2】:

      我不在 postgreSQL 上工作,但我想我可以回答你的问题。想想每个查询都是并行的。我是这么说的,因为有 2 个事务:当你插入时;其他人可以插入b;然后当你检查 b;您是否可以看到新数据取决于您的隔离设置(读取已提交或只是脏读)。

      另外请注意,在数据库中,有一种称为锁的技术:您可以锁定一个表,以防止在提交您的事务之前对其进行更改。

      希望

      【讨论】:

        猜你喜欢
        • 2011-04-14
        • 1970-01-01
        • 1970-01-01
        • 2010-10-26
        • 2018-11-16
        • 1970-01-01
        • 1970-01-01
        • 2020-03-10
        • 1970-01-01
        相关资源
        最近更新 更多