防止重复提交的最佳设计模式是什么?

5
我有一个设计模式一直在苦苦挣扎,如何最好地防止数据重复提交。
以下是步骤:
1.客户端提交带有唯一GUID的数据(由客户端生成的GUID-保证唯一)。 2.服务器端软件确保客户端guid在数据库中不存在。 3.开始事务。 4.处理数据(根据有效负载需要1-20秒)。 5.提交事务。
以下是几种情况: 如果客户端使用GUID“1”提交数据,然后在原始数据提交的步骤(5)之前再次使用GUID“1”提交数据,则事务将被处理两次。
在不使用信号量或阻塞的情况下,最佳的设计模式是什么?用户应该能够重新提交,以防第一次提交失败(服务器端硬件问题等)。
谢谢!

我认为这将成为架构存在缺陷的标志。如果可以的话,您可以重新设计以防止发生这种情况。 - James Black
5个回答

1

您可以通过使用读取未提交数据的查询来实现第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步失败。 - WeekendCoder
1
不一定。可以告诉用户在再次提交之前需要等待第一笔交易完成。阅读了被接受的答案后,我猜想他是在询问如何防止第二次提交,而第一次正在处理中;而不仅仅是确保如果第一次已经被处理,则第二次将失败。 - RyanHennig

1

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

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


0

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


这是从移动客户端断开连接。因此,问题在于用户的网络中断 - 认为事务失败了,因此他们会重新提交。 - WeekendCoder

0

你能将用户提供的数据进行哈希处理,并将其存储在表格中吗?在继续之前,请检查哈希值是否与以前的提交不匹配。


我猜你会使用客户端GUID和哈希来确保用户之间没有冲突。 - sonnyrao
我之前也考虑过类似的方案,但这样会使得流程变成非顺序执行。换句话说,流程将变为:
  1. 创建哈希并保存
  2. 检查哈希是否存在
  3. 检查提交ID是否存在
  4. 开始事务
  5. 处理提交
  6. 提交事务
如果第五步由于磁盘驱动器故障而失败,该怎么办?何时清空哈希表?
- WeekendCoder
如果第5行由于磁盘驱动器故障而失败,则整个事务将失败,步骤6根本不会发生,对吗?我不确定为什么你说它是非顺序的,你能再解释一下吗? - sonnyrao
另外,回答何时清除哈希表 - 您可以为哈希记录添加时间戳,当哈希表已满时清除旧记录以腾出空间供新记录使用。 - sonnyrao
Sonnyrao - 感谢您的回复 - 非常感激。问题是,如果步骤1中的哈希值不在交易中,则如果由于某些原因未处理交易,则不会回滚。 如果它在交易中,则会遇到与我最初发布的GUID相同的问题(即处理第二个提交的线程无法看到哈希值,因为它在尚未提交的事务中)。 - WeekendCoder

0
创建一个名为running_transactions的表,其中存储当前正在运行的事务的GUID。
1. 将GUID保存在running_transactions中。 2. 服务器端软件检查此表是否存在GUID,如果存在,则响应是“事务正在处理中”。 3. 服务器端软件在数据库中检查是否存在重复的GUID。如果存在,则响应是“重复的事务”。 4. 如果步骤2和3成功,则开始并完成事务。在此期间,如果请求再次使用相同的GUID在提交之前到达,则会被捕获在步骤2中。 5. 完成事务后,从running_transactions表中删除GUID。
注意-只有当该表保持轻量级(不超过1M条记录)且选择和删除操作快速时,此方法才有效。您还可以对GUID列进行索引。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接