数据库IsolationLevel和读写问题

时间:2019-06-25 05:42:36

标签: sql-server entity-framework concurrency transactions isolation-level

我一直在阅读有关数据库隔离级别和TransactionScope hereherehere的信息,但是似乎没有人回答我的问题。我遇到的问题是一个简单的读写问题。

下面将描述一个具体方案

  1. process1读取初始状态:ReadyForShipment
  2. process2读取状态:ReadyForShipment
  3. process1将状态更改为“已取消”并提交其交易
  4. process2将状态更改为“已发货”,这是无效的,因为不应取消商品。

Prcess1和process2无法互相通信,我希望数据库级解决方案能够保持这种状态。我知道隔离级别可序列化解决了该问题,因为在步骤2中获取的读取锁定阻止了步骤3的成功。

为了找到较少限制的隔离级别,我还阅读了ReadCommitted和行版本控制。根据{{​​3}}

的这段文字
  

锁定和行版本控制可防止用户读取未提交的数据   并防止多个用户尝试更改相同的数据   同时。在没有锁定或行版本控制的情况下,执行查询   通过返回数据可能会产生意外结果   数据库中尚未提交的文件

似乎暗示行版本控制可以解决读取和写入问题。在步骤4中,使用行版本控制,数据库应该能够检测到它正在尝试更改自步骤2中的读取以来其版本已更改的行。但是我的实验证明这不是行为。 将ReadCommited隔离和数据库的READ_COMMITTED_SNAPSHO设置为ON后,步骤4成功,状态更新为Shipped。

我的问题是,除了隔离级别“可序列化”之外,是否还有另一种数据库级别的解决方案来解决上述读写问题?

1 个答案:

答案 0 :(得分:1)

SQL Server中行的版本控制是什么(这也等同于其他数据库中的多版本并发控制MVCC的工作方式)-对于每个更改的行,它都会维护一个单独的版本,以便如果对该行有读取请求,它利用该版本而不是引用尚未提交的行。这是实现并发读取的一种更好的方式,然后不需要并发锁定,因此在所有主要数据库中都可以实现。现在,您可以了解为什么使用行版本控制(基于语句或事务级别的读取一致性)只能保证一致性读取(使用尚未提交的事务开始更改之前使用的数据版本)。

如果您仅从数据库方面寻求解决方案,我认为可序列化隔离级别是您最好的选择。假设没有多少事务会同时在同一数据行上进行操作,那么您持有锁定的时间将是最少的。

另一种解决方案是使用表中的version列使用开放式并发控制。后面的事务将在update子句中具有“ where version = 1”,该语句将返回0行更新,因为第一个事务已将版本增加到2行。在应用程序端可以将其视为逻辑错误,并相应地传播消息。