代码已经执行了两次coldfusion

时间:2013-11-23 19:36:03

标签: coldfusion

我有一个在CF任务中安排的ColdFusion文件,每30秒运行一次。此文件的目的是将响应表中的文本插入到订单表中。一切都工作得很酷,但现在有问题,即

随机1次中的6次,文件已执行两次,每行代码运行两次。所以订单被插入两次。

我已经检查过,如果存在响应ID为xxx的相同订单,请不要再次插入。但我仍然看到重复。任何帮助将不胜感激。

<cfquery name="getdupeordersinfile" datasource="#Application.ds#" dbtype="ODBC" username="#Application.UserName#" password="#Application.Password#">
        SELECT TOP 1 * from Orders
        Where ltrim(rtrim(smsresponseid)) = '#val(responseId)#'
    </cfquery>

    <cfif getdupeordersinfile.recordcount EQ 0>

        <cfquery name="getInsertInOrder" maxrows="1" datasource="#Application.ds#" dbtype="ODBC" username="#Application.UserName#" password="#Application.Password#" result="stResult">
            INSERT INTO Orders
               (....)
            values (...)

         </cfquery>


     </cfif>

由于

2 个答案:

答案 0 :(得分:2)

我会使用以下查询的一些变体,这些变体应该适用于任何现代SQL数据库:

INSERT INTO Orders
    (column1, column2, column3)
SELECT  column1, column2, column3
FROM    Responses
WHERE   1 = 1
    AND ...
    AND NOT EXISTS (
            SELECT  1
            FROM    Orders
            WHERE   ltrim(rtrim(smsresponseid)) = ltrim(rtrim(Responses.responseid))
        )

如果您输入的静态值不是来自数据库,也可以使用相同的技术。

INSERT INTO Orders
    (
        color,
        column1,
        column2
    )
SELECT  'red',
        <cfqueryparam value="#value1# ...>,
        <cfqueryparam value="#value2# ...>
WHERE   1 = 1
    AND NOT EXISTS (
            SELECT  1
            FROM    Orders
            WHERE   ltrim(rtrim(smsresponseid)) = ltrim(rtrim(Responses.responseid))
        )

我正在使用“SELECT 1”而不是“SELECT TOP 1”,因为您根本不需要获取任何字段。 “SELECT 1”只会返回1的字面值。当然,这是无用的,但无论如何你都不需要EXISTS子句中的实际值。此外,无论如何,数据库都不会在EXISTS子句中检索多条记录。

SQL Server: JOIN vs IN vs EXISTS - the logical difference

这篇文章特定于SQL Server,但我的经验表明大多数SQL数据库都是如此。

EXISTS和NOT EXISTS是解决此类问题的最佳解决方案,因为它具有性能影响,并且语法正确且清晰地描述了您想要的内容。

为什么会这样?

正如我以前没有提到的那样,这就是为什么代码可以执行两次(只是推测,但我已经看过了)。

假设此代码位于order-response.cfm中。想象一下,order-response.cfm被调用(由用户通过CFSCHEDULE调用并不重要)。请拨打此请求#1。在此之后,它立即再次被调用。请拨打此请求#2。

在请求#1中,检查查询运行并且不返回任何记录。然后(在请求#1中完成插入查询之前),检查查询在请求#2中运行。现在,请求#2中的检查查询也不返回任何结果。然后插入查询在请求#1中运行。然后插入查询在请求#2中运行(因为检查查询在运行时没有返回任何结果)。

这些请求相互接近以达到此效果的程度取决于代码运行的速度,而这又取决于(某种程度上)服务器所处的负载。如果您有数据库服务器被锁定的时间段(或相关的表被锁定),那么您可能需要等待解锁的事情,这可能会使这些步骤花费比您预期的更长的时间。

鉴于您的任务每30秒运行一次,数据库或ColdFusion的轻微减速可能导致这些请求重叠,从而产生此问题。

将它全部放在一个SQL语句中,使得该操作在某种程度上是原子的,并且不太可能遇到这种情况(尽管在极少数情况下它仍然会发生)。

我应该提到(我认为其他人已经做过)你应该在你的表中添加约束来拒绝重复的条目,以防止人们通过该级别。

答案 1 :(得分:0)

从响应表到您说的订单表。我的方法类似于:

insert into orders
(field1, field2, etc)
select field1, field2, etc
from response
where whatever
and somefield in
(select somefield 
from response
where -- here you specify the same conditions of the outer query
except
select somefield
from orders
)

确切的语法取决于您的rdbms。有些人使用减号而不是除外,其他人根本不支持这种语法。