如果数据已更改,则不更新结果集中的行

2022-09-04 04:50:58

我们正在从各种数据库类型(Oracle,MySQL,SQL-Server等)中提取数据。一旦它成功写入文件,我们希望将其标记为已传输,因此我们更新特定的列。

我们的问题是,用户有可能在此期间更改数据,但可能会忘记提交。使用“选择更新”语句阻止记录。因此,它可能会发生,我们将某些东西标记为已传输,但事实并非如此。

这是来自我们代码的摘录:

Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet extractedData = stmt.executeQuery(sql);
writeDataToFile(extractedData);
extractedData.beforeFirst();
while (extractedData.next()) {
    if (!extractedData.rowUpdated()) {
        extractedData.updateString("COLUMNNAME", "TRANSMITTED");
        // code will stop here if user has changed data but did not commit
        extractedData.updateRow();
        // once committed the changed data is marked as transmitted
    }
}

该方法返回 false,因为从技术上讲,用户尚未更改任何内容。有没有办法不更新行并检测数据是否在此后期阶段已更改?extractedData.rowUpdated()

不幸的是,我无法更改用户用于更改数据的程序。


答案 1

所以你想要

  • 遍历表中尚未导出的所有行
  • 将此数据导出到某个位置
  • 将这些行标记为导出,以便下一次迭代不会再次导出它们
  • 由于某一行上可能存在挂起的更改,因此您不希望弄乱该信息

怎么样:

You iterate over all rows. 

for every row 
   generate a hash value for the contents of the row
   compare column "UPDATE_STATUS" with calulated hash
   if no match
     export row
     store hash into "UPDATE_STATUS" 
      if store fails (row locked) 
         -> no worries, will be exported again next time
      if store succeeds (on data already changed by user) 
         -> no worries, will be exported again as hash will not match

这可能会进一步减慢导出速度,因为您必须迭代所有内容而不是所有内容,但您可能能够执行两项工作 - 一项(快速)迭代,另一项缓慢而彻底(哈希重新检查到位)WHERE UPDATE_STATUS IS NULLWHERE UPDATE_STATUS IS NULLWHERE UPDATE_STATUS IS NOT NULL

如果要避免存储失败/等待,则可能需要将哈希/更新的信息存储到复制主键和哈希字段值的第二个表中 - 这样,用户锁定主表根本不会干扰您的更新(就像在另一个表上一样)


答案 2

“用户 [...]可能忘记提交“> 用户要么提交,要么不提交。“忘记”提交等同于他的软件中的错误。

要解决此问题,您需要:

  • 启动具有隔离级别可序列化的事务,并在该事务中:
    • 读取数据并将其导出。以这种方式读取的数据将被阻止更新。
    • 更新您处理的数据。注意:不要使用可更新的 ,使用语句执行此操作。这样,您就不需要比 .ResultSetUPDATECONCUR_UPDATABLE + TYPE_SCROLL_SENSITIVECONCUR_READ_ONLY + TYPE_FORWARD_ONLY
  • 提交事务。

这样,错误软件将被阻止更新您正在处理的数据。

另一种方式

  • 在较低的隔离级别(默认)和该事务中启动TRANSACTIONREAD COMMITTED
    • 选择具有适当表提示的数据,例如,对于 SQL Server,例如:(大型数据集)或(小型数据集),或 .具有作为表的提示实际上等同于具有事务。请注意,如果锁的数量变得太高,则锁升级可能会将后两者升级到表锁。TABLOCKX + HOLDLOCKROWLOCK + XLOCK + HOLDLOCKPAGLOCK + XLOCK + HOLDLOCKHOLDLOCKSERIALIZABLE
    • 更新您处理的数据;注意:使用语句。丢失可更新/scroll_sensitive结果集。UPDATE
  • 提交事务。

同样的交易,有缺陷的软件将被阻止更新您正在处理的数据。


推荐