锁定选定的行,以便其他事务在读取时忽略它们

时间:2018-02-06 10:05:46

标签: sql database multithreading transactions db2

这个问题是关于优化的。 有问题的情况如下:

我有一个包含数据的表,应该由多个事务读取和操作。该表由三列组成:{id,message,status}。

ID   MESSAGE          STATUS
1    First Message    NEW 
2    Second Message   MOD
3    Third Message    FIN
....

如图所示,状态是以下三种状态之一:{new,mod,fin}。它们指示行是否为新行,此时正在处理或已成功处理。 我这样做,以便多个事务在此表上工作。事务将读取所有“NEW”消息并将状态更改为“MOD”,以指示它们正在处理并锁定它们。之后他们被处理。成功处理的行将设置为“FIN”,失败的行将设置为“NEW”,以便下一个事务将再次尝试这些。

除了更改状态外,该表是只读的。要处理的准确信息永远不会改变。

上述过程有效,但我认为它不必要地复杂化。我在这里寻找的是一个更简单的解决方案。我已经读过不同的隔离级别,但它们基本上都会导致行以某种方式锁定,以便其他事务必须等待。我不想那样。相反,我希望其他查询忽略那些已读取的行。

现在终于回答了这个问题: 是否可以在读取时锁定行,以便其他转换忽略它们,而不是等待解锁这些行的事务?

我想要这样的事情: 可以说这张桌子有30行。

  • 交易“reader1”读取30行,(id 1-30)。这些行现在已被锁定(最好对其他人都不可见)。
  • 事务“writer”插入20个新行。 (id 31-50)
  • 此时,“reader1”尚未完成。无需等待“reader1”完成,事务“reader2”只读取新的20行,因为其他行(1-30)被“reader1”隐藏
  • “reader1”和“reader2”完成。它们完成的顺序无关紧要,因为它们适用于析取数据集。

有没有办法在不需要状态栏的情况下执行此操作?

  • 使用的DBMS是IBM的DB2
  • 通过ODBC访问

1 个答案:

答案 0 :(得分:1)

  

有没有办法在不需要状态栏的情况下执行此操作?

简而言之,不,但不是由于锁定/并行问题。

实际上,您需要简单地使用该状态列,以便在处理系统最终出现故障时,您知道在重新启动时需要再次处理哪些行。它实际上使得更容易并行工作是一个附带的好处。

关于你的其余问题:

  

我已经阅读了不同的隔离级别,但它们基本上都会导致行以某种方式锁定,以便其他事务必须等待。我不想那样。相反,我希望其他查询忽略那些已读取的行。

......好吧,你很幸运,因为这不是你想要发生的事情。您的主要问题是,为了锁定读取的行,您不仅必须阻止其他进程读取这些行(因为通常只读共享锁),您必须阻止行从插入也是如此。但是,如果您使用写入锁定行,则交错过程变得更加简单和容易。

您需要的只是Cursor Stability

  

但是,如果更改了行中的任何数据,则会保持锁定,直到提交更改为止。

     

在此隔离级别下,当可更新游标位于该行上时,没有其他应用程序可以更新或删除行。在CS下,无法访问其他应用程序的未提交数据。 但是,不可重复的读取和幻像读取是可能的。

...允许其他处理器更新类似数据是非可重复读取的内容。我们实际上希望它们发生!我们不想要幻像读取(如果两行读取相同的数据然后尝试更新它会发生什么),但我们可以围绕它设计我们的应用程序。

执行此操作的一种方法是启动工作单元(这可能是隐式或显式的,具体取决于平台),然后发出更新语句:

UPDATE Transactions SET status = 'MOD'
WHERE status = 'NEW'

然后只需检索更新的行,以便知道要处理的内容:

SELECT id, message
FROM Transactions
WHERE status = 'MOD'

将它们标记为已完成:

UPDATE Transaction SET status = 'FIN'
WHERE status = 'MOD'

最后提交更改:

COMMIT

(请注意,此版本存在轻微弱点 - 如果系统在更新到'FIN'之后但在提交之前发生故障,则该行将重置为'NEW',这可能是它自己的问题。但至少'MOD'将正确回滚)