关系数据库的隔离级别和select for update之间有什么关系?
如果我对SQL Server使用普通的JDBC连接,并将隔离级别设置为READ_REPEATABLE并使用一个简单的select,我会在可重复读取中看到不一致吗?或者,我应该始终使用select for update来避免事务中不一致的可重复读取吗?如果是这样的话,隔离级别是如何处理的,它们将如何发挥作用?
发布于 2019-08-11 23:57:20
SQL Server没有select ... for update语法。SQL Server中的等效方法是使用UPDLOCK表提示。
在原子事务中读取行并立即更新同一行时,将使用此提示。例如
declare @balance = (select balance from account where accountId = @id)
update account set balance = @balance + @amount where accountId = @id在READ COMMITTED时,或者在没有多语句事务的任何隔离级别中,多个会话可以运行第一个查询,并且在更新余额时丢失更新。
使用REPEATABLE READ或SERIALIZABLE隔离级别可以防止这种update异常,但如果有任何并发事务已读取该行,并且如果其他事务之一试图更新该行,则它们会阻塞第一个写入器,从而导致死锁。
大多数情况下,这种行为不值得为处理死锁而付出性能、成本和烦恼。因此,您可以使用'select for update‘,也就是UPDLOCK,在读取时在行上放置一个U锁,并阻止后续的读取器获取冲突的锁。
例如
declare @balance = (select balance from account with (updlock) where accountId = @id)
update account set balance = @balance + @amount where accountId = @id发布于 2019-08-11 23:50:44
不需要使用提示或其他方式干预默认行为。SQL Server保证每个您声明的所需级别的事务隔离级别。可重复读取保证了在一个事务中,您的语句将看到所读取的数据的一致视图,但不能保证不会有幻象行。为了避免后者,您需要使用SERIALIZABLE。隔离度越高,并发惩罚当然越高。
有关更深入的讨论,请参阅JDBC Page for isolation levels和general page for SET TRANSACTION ISOLATION LEVEL。
HTH
发布于 2019-08-11 23:54:03
不完全确定您所说的“不一致的可重复读取”是什么意思,但是使用SQL Server中的REPEATABLE READ隔离级别,共享锁将一直保留到事务结束。只有提交的数据才会返回,其他会话无法修改读取的行,直到事务提交(或在没有显式事务的情况下自动提交)。
REPEATABLE READ不会阻止其他会话插入新行,因此在同一事务中重新运行相同的查询可能会返回最初未返回的新行(幻影读取)。
The documentation更详细地描述了这一点,以及其他事务隔离级别。
https://stackoverflow.com/questions/57451018
复制相似问题