【问题标题】:Database IsolationLevel and read write problem数据库 IsolationLevel 和读写问题
【发布时间】:2019-11-06 21:45:45
【问题描述】:

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

下面描述一个具体的场景

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

进程 1 和进程 2 不相互通信,我希望数据库级别的解决方案能够保持这种状态。我知道隔离级别 Serializable 解决了这个问题,因为在 step2 中获取的读锁阻止了 step3 成功。

为了找到限制较少的隔离级别,我还阅读了 ReadCommitted 和行版本控制。根据here的这篇文字

锁定和行版本控制可防止用户读取未提交的数据 并防止多个用户尝试更改相同的数据 同时。没有锁定或行版本控制,查询执行 针对该数据可能会通过返回数据产生意想不到的结果 还没有提交到数据库中

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

我的问题是,除了隔离级别Serializable之外,对于上面描述的读写问题,还有其他数据库级别的解决方案吗?

【问题讨论】:

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


【解决方案1】:

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

如果您正在寻找纯数据库方面的解决方案,我认为 Serializable 隔离级别是您最好的选择。假设不会有多少事务同时在同一数据行上工作,那么您保持锁定的时间可能会很短。

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

【讨论】:

  • 感谢您描述真正的行版本控制。 Microsoft 文档使它听起来像您描述的版本控制列解决方案。我想我必须实现自己的。对内置功能的期望过高
猜你喜欢
  • 2017-09-06
  • 2019-07-06
  • 2012-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多