私の意見では、トリガーでメールを送信することは最適ではありません。
代わりに、キューテーブルに挿入するだけで、テーブルをチェックして電子メールを送信するプロセスを頻繁に実行する必要があります。
電子メールの手順でエラーが発生した場合はどうなりますか?これにより、ジョブの完了ステータスが強制的にロールバックされます。それが軽微なのか、恐らく壊滅的なのかを知っているのはあなただけです。ただし、DBのベストプラクティスは、DML操作中に拡張I/Oを実行しないことです。
CREATE TRIGGER TR_Jobs_EnqueueEmail_IU ON dbo.Jobs FOR INSERT, UPDATE
AS
SET NOCOUNT ON;
INSERT dbo.EmailQueue (UserID, JobCode)
SELECT UserID, JobCode
FROM
Inserted I
LEFT JOIN Deleted D
ON I.JobCode = D.JobCode -- or proper PK columns
WHERE
IsNull(D.Status, 'R') <> 'D'
AND I.Status = 'D';
必要なテーブル:
CREATE TABLE dbo.EmailQueue (
QueuedDate datetime NOT NULL
CONSTRAINT DF_EmailQueue_QeueueDate DEFAULT (GetDate()),
UserID int NOT NULL,
JobCode int NOT NULL,
CONSTRAINT PK_EmailQueue PRIMARY KEY CLUSTERED (QueuedDate, UserID, JobCode)
);
CREATE TABLE dbo.EmailSent (
SentDate datetime NOT NULL
CONSTRAINT DF_EmailSent_SentDate DEFAULT (GetDate()),
QueuedDate datetime NOT NULL,
UserID int NOT NULL,
JobCode int NOT NULL,
CONSTRAINT PK_EmailSent PRIMARY KEY CLUSTERED (SentDate, QueuedDate, UserID, JobCode)
);
次に、SQLジョブから1分に1回、次のストアドプロシージャを実行します。
CREATE PROCEDURE dbo.EmailProcess
AS
DECLARE @Email TABLE (
QueuedDate datetime,
UserID int,
JobCode int
);
DECLARE
@EmailAddress nvarchar(255),
@JobCode int;
WHILE 1 = 1 BEGIN
DELETE TOP 1 Q.*
OUTPUT Inserted.QueuedDate, Inserted.UserID, Inserted.JobCode
INTO @Email (QueuedDate, UserID, JobCode)
FROM dbo.EmailQueue Q WITH (UPDLOCK, ROWLOCK, READPAST)
ORDER BY QueuedDate;
IF @@RowCount = 0 RETURN;
SELECT @EmailAddress = U.EmailAddress, @JobCode = E.JobCode
FROM
@Email E
INNER JOIN dbo.User U
ON E.UserID = U.UserID;
EXEC dbo.SendMyEmail @EmailAddress, @JobCode;
DELETE E
OUTPUT QueuedDate, UserID, JobCode
INTO dbo.EmailSent (QueuedDate, UserID, JobCode)
FROM @Email E;
END;
私が使用した削除パターンとロックは非常に特別に選択されています。それらを変更したり、何らかの方法で削除パターンを変更したりすると、それが壊れるのはほぼ確実です。ロックと並行性の処理は困難です。変更しないでください。
注:SQL Serverで何もチェックせずに、上記のすべてを入力しました。タイプミスがある可能性があります。許してください。