【问题标题】:Solution for previewing user changes and allowing rollback/commit over a period of time预览用户更改并允许在一段时间内回滚/提交的解决方案
【发布时间】:2011-06-11 03:55:19
【问题描述】:

我在尝试解决问题时询问了few questions today

我们有一个复杂的数据结构,其中所有各种实体都紧密互连,几乎所有实体都严重依赖/依赖于其他类型的实体。

该项目是一个网站(MVC3,.NET 4),所有的逻辑都是在业务层使用 LINQ-to-SQL (2008) 实现的。

我们需要做的是让用户在他们进行更改时“锁定”系统(还有其他与数据库无关的原因,我不会在这里讨论)。当该用户进行更改时,我们希望能够向他们展示他们正在更新的实体的原始状态,以及他们所做更改的“预览”。完成后,他们需要能够回滚/提交。

我们考虑了以下选项:

  1. 在用户进行多项更改所花费的时间长度内保持打开事务很糟糕,因此已经过时了。
  2. 在内存中保存所有数据的副本(或缓存到磁盘)是一种选择,但其中有很多,所以看起来不合理。
  3. 维护一组辅助表,或尝试使用会话状态来存储更改,但这很复杂且难以维护。
  4. 使用两个数据库,通过连接字符串在它们之间翻转,并使用 T-SQL 管理复制,在提交/回滚后将它们重新同步。 IE。开启/关闭、强制快照、反转方向等。

对于一个相对易于维护的解决方案,我们感到有些困惑。有什么建议吗?

【问题讨论】:

    标签: asp.net sql-server linq-to-sql transactions session-state


    【解决方案1】:

    我们对类似问题的解决方案是使用一个锁定表,该表在我们的系统中为每个实体类型保存锁定。当客户端应用程序想要编辑实体时,我们会执行“GetWithLock”,它会为客户端获取实体数据的最新版本并获取锁定(与锁定表一起存储的 GUID)实体类型和实体 ID)。这可以防止其他用户编辑同一实体。当您通过更新提交更改时,您可以通过从锁定表中删除锁定记录来释放锁定。由于存储过程是我们用于与数据库交互的 api,这允许一种非常直接的方式来锁定/解锁对特定实体的访问。

    在客户端,我们在 UI 模型类上实现 IEditableObject。我们的模型类包含对在服务调用中检索到的服务实体实例的引用。这允许 UI 执行 Begin/End/Cancel Edit 并根据需要执行提交或回滚。通过持有原始服务实体的实例,我们能够看到原始和当前数据,这将允许用户获得您正在寻找的“预览”。

    虽然我们的解决方案没有实现 LINQ,但我认为我们的方法中没有任何独特之处会阻止您也使用 LINQ。

    HTH

    【讨论】:

    • 不完全符合他的要求,但这里有很多好主意。
    • 确实不错,但不是我们想要的。这基本上是我列表中的选项 2,因为我们需要锁定一个(非常)大的数据集。
    • 尽管我在上面发表了评论,但这是我最终使用的解决方案,因此我将其标记为答案。我不确定这个答案还是来自@Quassnoi 的答案是否最正确,但它在我的情况下效果最好。
    【解决方案2】:

    考虑一下:

    1. 长事务使系统的可扩展性降低。如果执行 UPDATE 命令,更新锁会持续到提交/回滚,防止其他事务继续进行。
    2. 第二个表/数据库可以通过并发事务进行修改,因此您不能依赖表中的数据。唯一的方法是锁定它 => 见 no1。
    3. 某些数据引擎中的可序列化事务使用表中的数据版本。因此,在执行第一个 cmd 之后,事务可以在 cmd 执行时间内看到可用的确切数据。这可能有助于您显示用户所做的更改,但您不能保证将它们保存回存储中。
    4. DataSets 包含旧/新版本的数据。但很遗憾,这超出了您的技术目标。

    【讨论】:

    • 我们考虑选项 1 的原因是一次只有一个用户修改将被锁定的数据。但它闻起来。关于您列表中的 3,我将更新我的问题以澄清我的意思。
    【解决方案3】:

    使用一组辅助表。

    问题是您的连接应该看到两个版本的数据,而其他连接应该只看到一个(或两个,其中一个是自己的)。

    虽然理论上是可行的并且在Oracle 中使用闪回实现,但SQL Server 本身并不支持它,因为它无法查询以前版本的记录。

    您可以发出这样的查询:

    SELECT  *
    FROM    mytable
    AS OF TIMESTAMP
            TO_TIMESTAMP('2010-01-17')
    

    Oracle,但不在SQL Server

    这意味着您需要自己实现此功能(将新版本的行放入您自己的表中)。

    【讨论】:

      【解决方案4】:

      听起来像一个丑陋的问题,并提出了一大堆你将无法解决的问题。我在阅读您的问题时得到了以下想法,虽然它“闻起来”和您列出的其他问题一样糟糕,但它可能会帮助您找到最终的解决方案。

      首先,如@user580122 所述,拥有某种锁定系统来标记/记录其中一个事务正在进行的事实。 (一定要包括某种定期自动检查,以测试丢失或放弃的交易!)

      接下来,对于您对数据库所做的每一次更改,以某种方式将其记录在应用程序中或某处的专用表中。这个想法是,给定状态 X 的数据库副本,您可以随时重新运行用户提交的步骤。

      接下来是弄清楚如何使用数据库快照。在 BOL 中阅读这些内容;一般的想法是您创建数据库的时间点快照,对它做任何您想做的事情,并最终将其丢弃。 (仅适用于 SQL 2005 及更高版本,仅限企业版。)

      所以:

      • 用户出现并启动其中一项元交易。
      • 在数据库中标记了一个标志,显示正在发生的事情。如果新事务已在进行中,则无法启动新事务。 (同样,不时检查丢失的交易!)
      • 对数据库所做的每一次更改都会以可以重复的方式进行跟踪和记录。
      • 如果用户决定取消交易,您只需删除快照,没有任何改变。
      • 如果用户决定保留事务,您可以删除快照,然后立即将记录的更改重新应用到“真实”数据库。这应该可行,因为您的要求意味着,当有人在处理其中之一时,没有其他人可以触及数据库的相关部分。

      是的,这确实有味道,它可能不适用于您的问题。希望这里的想法可以帮助您解决问题。

      【讨论】:

        猜你喜欢
        • 2011-07-20
        • 2014-08-06
        • 2011-06-11
        • 1970-01-01
        • 2021-05-06
        • 2022-11-01
        • 1970-01-01
        • 2014-10-20
        • 1970-01-01
        相关资源
        最近更新 更多