我正在使用事务来更改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。
答案 0 :(得分:1)
辛指出,这取决于isolation level。
在默认READ COMMITTED
级别,来自其他会话的记录将在提交时显示;如果你根本没有开始交易,你会看到相同的记录(当然,其他过程会看到你的插页出现在不同的时间)。
使用REPEATABLE READ
,您的查询将不会在事务开始后看到其他会话提交的任何记录。但是,虽然您不必担心交易期间SELECT COUNT(*)
更改的结果,但您不能认为此结果在您提交时仍然准确无误。
使用SERIALIZABLE
提供了最强有力的保证:如果您的脚本在获得对数据库的独占访问权时做了正确的事情,那么它将在存在其他可序列化事务时做正确的事情(或者它将彻底失败) 。但是,这意味着所有可能干扰您的事务必须使用相同的隔离级别(这是有代价的),所有必须准备好在序列化失败的情况下重试其事务。
当可序列化事务不是一个选项时,通常通过显式锁定并发写入来防止竞争条件。它通常足以锁定一系列记录,但您无法准确锁定COUNT(*)
的结果;在您的情况下,您可能需要lock the whole table。
答案 1 :(得分:0)
我不是在研究postgreSQL,但我想我可以回答你的问题。想想每个查询都是并行的。我是这样说的,因为有2个交易:当你插入一个;其他人可以插入b;然后当你检查b;是否可以看到新数据取决于您的隔离设置(读取已提交或只是脏读)。
另请注意,在数据库中,有一种称为锁的技术:您可以锁定表,以防止在提交事务之前将其更改为其他人。
希望