事务如何在读取数据库的上下文中工作?

时间:2016-03-02 00:21:13

标签: postgresql acid

我正在使用事务来更改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,然后根据INSERT的结果有条件地执行另一个SELECT

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

如果它有所作为,我正在使用PostgreSQL。

2 个答案:

答案 0 :(得分:1)

辛指出,这取决于isolation level

在默认READ COMMITTED级别,来自其他会话的记录将在提交时显示;如果你根本没有开始交易,你会看到相同的记录(当然,其他过程会看到你的插页出现在不同的时间)。

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

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

当可序列化事务不是一个选项时,通常通过显式锁定并发写入来防止竞争条件。它通常足以锁定一系列记录,但您无法准确锁定COUNT(*)的结果;在您的情况下,您可能需要lock the whole table

答案 1 :(得分:0)

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

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

希望