CFThread批处理过程 - 多次处理记录

时间:2016-09-03 04:55:59

标签: sql sql-server database sql-server-2005 coldfusion

我们通过批处理发送大量电子邮件。此过程在CFThread内部运行。从SQL Server检索每个记录集。当我们遍历电子邮件时,我们会将记录更新为已发送。

当我们每分钟运行一次这个过程时,它运行正常。每隔30秒运行一次,它会多次开始处理记录。

虽然我们将记录标记为“拉”,但仍然面临着问题。 看起来当第一个请求仍在处理时,第二个请求开始。第二个请求在第一个请求可以将它们标记为“已拉”之前检索记录。所以相同的记录被处理两次。

我不想锁定表格,因为在我提取记录时,我也会发送电子邮件并更新在同一张表中发送的其他记录。

数据库:(伪代码

BEGIN
DECLARE @MyTempTable table(
ID INT  IDENTITY(1,1) NOT NULL,
emailBody varchar(max),
eMailfromdisplay varchar(200),
eMailFromAdr varchar(200),
eMailsubject varchar(200),
emailAdr varchar(200),
FirstName_vch varchar(250),
LastName_vch varchar(250),
Sent INT,
pulled INT,
masterEmailTableID BIGINT
);


insert into @MyTempTable
select Distinct top 1000
    emailBody,
    eMailfromdisplay,
    eMailFromAdr,
    eMailsubject,
    emailAdr,
    FirstName,
    LastName,
    Sent,
    pulled ,
    masterEmailTableID
from 
    emailMasteTable 

where 
    pulled  = 0 and
    Sent    = 0



SELECT TOP 1000 id
    ,masterEmailTableID
    ,Email_adr
    ,firstName
    ,LastName
    ,Sent
    ,pulled
 FROM @MyTempTable where sent = 0 and pulled = 0    



  -- Other tables status updates 

update emailMasteTable set pulled = 1 where EmailID IN (Select distinct masterEmailTableID from @MyTempTable);

END

ColdFusion :( 伪代码

<cfquery  name="getMessages">
    exec spGetEmailMessages
</cfquery>


<cfoutput query="getMessages">

    <cfmail>
    <!--- Email Stuff --->


        <cfquery>
            update emailMasteTable set sent = 1 where EmailID = #getMessages.masterEmailTableID#;
        </cfquery>
    </cfmail>
</cfoutput>

1 个答案:

答案 0 :(得分:0)

我建议您阅读how locking works in SQL Server。这是一个很大的主题,但简而言之,简单地将语句包装在存储过程中并不意味着访问以某种方式单线程或者其他线程被神奇地阻止抓取同一组记录。当前代码中没有任何内容阻止同一批记录被&#34; 读取&#34;在UPDATE启动之前多次。事实上,涉及的线程越多,并且频繁的间隔,多个线程将处理相同记录的可能性越大。

将一批记录标记为&#34;正在使用&#34;是不够的。 之后检索它们。在检索时,必须标记。例如,运行UPDATE以标记一批记录。使用OUTPUT clause捕获id并将它们存储在某种临时表中。然后JOIN回到临时表以执行任何其他操作。鉴于它是一个经常访问的表,您应该进行一些分析以确定最佳/最有效的方法。

-- Stores next batch of ids
DECLARE @TempTable TABLE ( masterEmailTableID BIGINT );

-- Flag next batch as being "processed"
-- Note: Without an order by clause result order is arbitrary
UPDATE TOP (1000) BigTable
SET    Pulled = 1
OUTPUT inserted.masterEmailTableID INTO @TempTable
WHERE  Pulled = 0
AND    Sent = 0

-- do other queries .... 

-- Return details for current batch
SELECT  main.masterEmailTableID
        , main.masterEmailTableID
        , ... other columns 
FROM    BigTable main INNER JOIN @TempTable tmp ON tmp.masterEmailTableID = main.masterEmailTableID
GO

旁注,您可能还会考虑在表格中添加唯一的批次编号,以便更新批量状态,而不是单独更新项目。