我不确定我是否在标题中加入正确的词语来解释。但就是这样。
应用程序:Coldfusion / MySQL
在错误的互联网接收期间异常发生的问题在第一次完成之前触发了双重请求。结果得到了两个数据库条目。
应用程序仅处理具有SELECT查询的双重请求,以检查db中是否已有相同的记录。在这种情况下,使用UPDATE语句更新旧记录。否则,INSERT语句用于插入新记录。 SELECT / INSERT / UPDATE包含在CFTRANSACTION中。
<cftransction>
<cfquery></cfquery> //SELECT
<cfif SELECT.found>
<cfquery></cfquery> //UPDATE
<cfelse>
<cfquery></cfquery> //INSERT
</cfif>
</cftransaction>
在大多数情况下,当两个请求有一些延迟时,它可以正常工作。要重现这个问题,
当REQUEST.2 SELECT在REQUEST.1 INSERT之前运行时,上面的代码可能会插入两个条目。服务器端可能有什么解决方案?
在第一个请求完成之前,在客户端处理并禁用后续请求。但是想要在服务器上保护它。
答案 0 :(得分:1)
所以我使用了@Leigh提供的解决方案来评论原始问题。只是回答让它脱颖而出以及我必须做些什么来实际使用这个解决方案。
您是不是使用SELECT .. INSERT方法而是查看了REPLACE或INSERT ... ON DUPLICATE KEY UPDATE等数据库选项? - Leigh
虽然两种解决方案似乎都很好解决问题,但REPLACE更具吸引力,因为它只需要我在“REPLACE”中更改查询中的“INSERT”关键字
通过文档的快速概述,REPLACE完全替换并像INSERT语句一样工作,但仅在找到具有重复PRIMARY KEY或UNIQUE索引的行时才执行此目的。
1-因为我需要三个列在这个意义上是唯一的,我在插入它们之前使用SELECT在WHERE子句中使用它。在REPLACE可以限制重复行之前,我必须在这三列上添加一个UNIQUE索引。
2-如果找到重复的行,则REPLACE首先删除旧行,然后插入新行。此过程还可能会丢失表中其他列的某些值。但是在我的应用程序中,这些列在每个REQUEST上都会更新,而这些列的值是从其他表派生的。所以这对我来说不是问题,因为可以为插入的新行更新数据。
答案 1 :(得分:0)
&lt; cftransaction&gt;会将select + insert / update查询组合在一起,但不会阻止执行第二个+请求,即使在事务完成之前也是从同一个浏览器执行。
我遇到过与IE浏览器类似的问题。用户可以垃圾邮件点击提交,IE会在每次点击提交按钮时提交。
我使用的最常见的解决方案是在点击后禁用提交按钮,或者用一条类似&#34;等待,提交表单的消息替换(隐藏)它。 &#34 ;.我已经使用JavaScript / jQuery完成了这项任务。它不是100%有效,并且取决于正在使用的浏览器以及是否启用了JavaScript。
另一个选择是使用命名的&lt; cflock&gt;确保代码只能作为批处理执行。如果有几个人同时使用该表单,这可能会导致性能瓶颈。所以,我打算使用会话变量作为命名&lt; cflock&gt;的一部分。名称。这样,锁对每个用户都是唯一的。
以下是CF 11示例:
<cflock name="lckInsUpdt_#listFirst(session.sessionid, '.')#" timeout="300" throwontimeout="no" type="exclusive">
<cftransction>
<cfquery></cfquery> //SELECT
<cfif SELECT.found>
<cfquery></cfquery> //UPDATE
<cfelse>
<cfquery></cfquery> //INSERT
</cfif>
</cftransaction>
</cflock>