【问题标题】:Stored procedure not as defensive as it looks存储过程不像看起来那样具有防御性
【发布时间】:2012-10-23 21:55:13
【问题描述】:

我有几个结构如下的存储过程:

USE [WHouse]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[pr_Alert_Dly]
AS
    IF (SELECT LastRunDate FROM WHouse.dbo.AlertRunDates WHERE NameDescription = 'X' ) < (SELECT CONVERT(DATE, GETDATE()))
    BEGIN
       --================
       --need to comment the following out if trying to re-run
       UPDATE x 
       SET  x.LastRunDate = CONVERT(DATE,GETDATE())
       FROM WHouse.dbo.AlertRunDates x
       WHERE [NameDescription] = 'X' 
       --================

       --===============
       --DO A LOAD OF STUFF IN HERE 
       --INCLUDING USING DB_SENDMAIL TO EMAIL 20 PEOPLE
       --===============

    END

我的同事已经建立了一个报告系统(使用过程/SSIS),该系统每 10 分钟循环一次,只要存储过程完成且没有错误,它就会在控制表中标记为完成。

我不明白的是,即使上面抛出错误,为什么它会在同一批次中多次重复BEGIN / END 之间的部分?

如果防御不够,如何防御我的同事系统导致相同的电子邮件每 10 分钟分发一次?!

【问题讨论】:

  • 可能是外部事务被回滚或中止?您可以回滚更新,但不能回滚已发送的电子邮件。也许使用队列表和后台进程而不是立即主动发送电子邮件。
  • @usr 如果是数据库邮件,它是异步的(使用服务代理),所以唯一的风险是你不能回滚它。 :-) 就是说,我同意你的看法。这些电子邮件应该发送到其他地方(无论是 SQL Server 中的后台进程,还是完全外部)。
  • @AaronBertrand - 好的,所以有一个表“EmailQueue”,其中包含BodyTOCC 等字段,然后(使用代理的经验不多)代理以某种方式检查表,如果它看到新条目,它将运行一个存储过程来构建并使用 DB_SendMail 发送邮件?
  • 代理将运行一个存储过程来检查表中的新条目,发送它需要的任何电子邮件,然后将条目标记为已处理。有时存储过程将由代理运行,但没有任何要处理的内容。没关系。还有其他方法可以做到这一点(例如服务代理),但代理是迄今为止最简单的。
  • 那么这不是一个真正的队列表......您回到了必须等待触发器完成的初始事务。您只是无缘无故地添加了一个附加表。创建代理工作有什么难的?

标签: sql sql-server tsql stored-procedures sql-server-2008-r2


【解决方案1】:

最终废弃了 OP 中的模式,并使用了 Aaron 在 OP 的 cmets 中提出的建议,即创建了一个 EmailQueue 表并设置了一个每 5 分钟循环一次的后台进程(通过 Agent)。此过程会扫描EmailQueue 表中的任何新记录,并在需要时发送电子邮件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多