我们通过批处理发送大量电子邮件。此过程在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>
答案 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
旁注,您可能还会考虑在表格中添加唯一的批次编号,以便更新批量状态,而不是单独更新项目。