【问题标题】:What is the best design pattern for preventing duplicate submissions?防止重复提交的最佳设计模式是什么?
【发布时间】:2010-10-17 03:17:47
【问题描述】:

我一直在努力解决如何最好地防止重复发布数据的设计模式。

步骤如下:

  1. 客户端使用唯一的 guid 提交数据(客户端生成的 guid - 保证唯一)
  2. 服务器端软件确保数据库中尚不存在客户端 guid
  3. 开始交易
  4. 处理数据(可能需要 1-20 秒,具体取决于负载)
  5. 提交交易

以下是场景: 客户端提交guid为“1”的数据,然后在第(5)步之前重新提交guid为“1”的数据,为原始数据提交,然后交易被处理两次。

在不使用信号量或阻塞的情况下防止这种情况的最佳设计模式是什么?用户应该能够重新提交,以防第一次提交由于某种原因(服务器端的硬件问题等)失败。

谢谢!

【问题讨论】:

  • 我认为这将表明架构存在缺陷。如果可以的话,您可以重新设计以防止这种情况发生。

标签: database design-patterns transactions


【解决方案1】:

将 GUID 存储在带有 SQL UNIQUE 约束的列中。

当您尝试(在事务中)插入第二个重复的 GUID 时,操作将失败,此时您回滚整个事务。

【讨论】:

    【解决方案2】:

    您可以使用读取未提交数据的查询来实现第 2 步。例如,如果您使用的是 MS SQL Server,您可以这样做:

    IF NOT EXIST(SELECT * FROM SomeTable (NOLOCK) WHERE Guid = @ClienGUID)
    BEGIN
       -- Insert the GUID ASAP in the transaction so that the next query will read it
       -- Do steps 3-5
    END
    

    这里的关键是(NOLOCK)提示,它读取未提交的数据

    【讨论】:

    • 但是如果它读取了未提交的数据,然后原来的事务失败了,那么用户就会被告知它已经被错误地处理了,对吧?即在第 2 步中返回一个响应,说明它已经被处理(到第二次提交) - 然后原始提交在第 4 步失败。
    • 不一定。可以告诉用户,他们需要等待第一笔交易完成,然后再尝试再次提交。在阅读了接受的答案后,我想我认为他在寻求一种方法来防止在处理第一个提交时第二次提交;不是简单地确保如果第一个已经处理,它会失败。
    【解决方案3】:

    我不知道您使用什么来开发前端,但在 Web 应用程序中,您可以使用 ajax 检查服务器转换状态,在等待时为用户提供一些反馈,同时禁用提交选项。

    【讨论】:

    • 这将与移动客户端断开连接。所以,问题是用户网络掉线 - 认为交易失败,所以他们重新提交。
    【解决方案4】:

    您能否对用户提供的数据进行哈希处理并将其存储在一个表中——在继续之前检查哈希是否与之前的任何提交不匹配?

    【讨论】:

    • 我猜你会使用带有哈希的客户端 guid 来确保用户之间没有任何冲突
    • 我当时在想一些类似的事情,但这使它成为一个非连续的过程。也就是说,流程变成了: 1. 创建哈希并保存 2. 检查哈希是否存在 3. 检查提交id是否存在 4. 开始事务 5. 处理提交 6. 提交事务 如果第5行由于a而失败我该怎么办磁盘驱动器故障?什么时候清除哈希表?
    • 如果第 5 行由于磁盘驱动器故障导致整个事务失败,并且第 6 步根本不会发生,对吧?我不知道你为什么说它是非连续的,你能再解释一下吗
    • 另外,回答什么时候清除哈希表——你可以给哈希记录加上时间戳,当哈希表满时清除旧记录为新记录腾出空间
    • Sonnyrao - 感谢您的回复 - 非常感谢。问题是,如果来自步骤 1 的哈希不在事务中,那么如果由于某种原因未处理事务,它将不会回滚。如果它在事务中,那么它会遇到与我最初发布的 GUID 完全相同的问题(即处理第二次提交的线程不会看到哈希,因为它在尚未提交的事务中)。
    【解决方案5】:

    创建一个表 running_transactions,用于存储当前正在运行的事务的 GUID,即

    1. 将 GUID 保存在 running_transactions 中。
    2. 服务器端软件检查此表中是否存在 GUID,如果存在,则响应为“正在处理的事务”。
    3. 服务器端软件在 DB 中检查重复的 GUID。如果存在,则响应为“重复交易”。
    4. 如果 2 和 3 成功,则开始事务并完成它。在此期间,如果请求在提交之前再次带有相同的 GUID,它将在步骤 2 中被捕获。 5.事务完成后,从 running_transactions 表中删除 GUID。

    注意-这种方法仅在此表保持轻量(不超过 1Mrecords)并且选择和删除工作快速时才有效。您还可以索引 GUID 列。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-25
      • 2018-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多