當 Database mail 無法在 SQL Server 中傳送訊息時,「交易無效」錯誤

本文可協助您解決 Database mail 無法傳送訊息的問題。

原始產品版本: SQL Server 2012、SQL Server 2014、SQL Server 2016、Linux 上的 SQL Server 2017、Windows 上的 SQL Server 2017
原始 KB 編號: 4502457

徵兆

假設執行 Microsoft SQL Server 的用戶無法傳送 Database Mail。 在此情況下,Database mail 記錄檔 (sysmail_event_log) 會顯示下列專案:

例外狀況資訊: 例外狀況類型:Microsoft.SqlServer.Management.SqlIMail.Server.Common.BaseException
訊息:交易無效。
數據:System.Collections.ListDictionaryInternal
TargetSite: Void ValidateConnectionAndTransaction()
HelpLink:NULL
來源:DatabaseMailEngine
StackTrace 資訊: at Microsoft.SqlServer.Management.SqlIMail.Server.DataAccess.ConnectionManager.ValidateConnectionAndTransaction()
at Microsoft.SqlServer.Management.SqlIMail.Server.DataAccess.ConnectionManager.RollbackTransaction()
at Microsoft.SqlServer.Management.SqlIMail.IMailProcess.QueueItemProcesser.GetDataFromQueue(DataAccessAdapter da, Int32 lifetimeMinimumSec)
at Microsoft.SqlServer.Management.SqlIMail.IMailProcess.QueueItemProcesser.ProcessQueueItems(String dbName, String dbServerName, Int32 lifetimeMinimumSec, LogLevel loggingLevel, Byte[] encryptionKey, Int32 connectionTimeout)',@proc

注意

  • 片語在 [訊息] 欄位中不再有效,表示交易不再有效
  • 您可能會在應用程式記錄檔中看到相同的訊息。 郵件訊息會在 中 sysmail_unsentitems保持「重試」狀態,而且會保持未傳送狀態,直到DatabaseMail.exe外部程式可以順利執行為止。

原因

SQL Server 預設連線選項會使用 SET NUMERIC_ARITHABORT ON。 當您執行 sp_send_dbmail時,郵件訊息會排入 ExternalMailQueue 佇列。 當訊息出現在佇列中時,啟用預存程式會觸發DatabaseMail.exe外部可執行檔。 當DatabaseMail.exe連線到 SQL Server 時,它會執行sp_readrequest以從佇列讀取訊息。 在執行 sp_readrequest期間,您可能會注意到例外狀況發生。 下列 SELECT 語句會在 中 sp_readrequest 執行(您必須收集語句層級追蹤才能看到此 SELECT 語句):

DatabaseMail - DatabaseMail - Id\<ProcessId>        \<NTUserName>        \<SPID>                \<StartTime>              msdb        \<LoginSid>  \<SessionLoginName>
-- network protocol: TCP/IP
set quoted_identifier on
set arithabort off
set numeric_roundabort on
set ansi_warnings on
set ansi_padding on
set ansi_nulls on
set concat_null_yields_null on
set cursor_close_on_commit off
set implicit_transactions off
set language us_english
set dateformat mdy
set datefirst 7
set transaction isolation level read committed
2 - Pooled        1        1 - Non-DAC
RPC:Starting <BinaryData> 4 <NTUserName> DatabaseMail - DatabaseMail - Id<ProcessId> <NTUserName> <SPID> <StartTime> sp_readrequest msdb <LoginSid> <SessionLoginName> exec sp_readrequest @receive_timeout=600000

SP:StmtStarting <BinaryData> 4 <NTUserName> DatabaseMail - DatabaseMail - Id<ProcessId> <NTUserName> <SPID> <StartTime> sp_readrequest msdb <LoginSid> <SessionLoginName>

SELECT @mailitem_id = MailRequest.Properties.value('(MailItemId)[1]', 'int')  
FROM @xmlblob.nodes('
declare namespace requests="https://schemas.microsoft.com/databasemail/requests]";/requests:SendMail')

AS MailRequest(Properties)
If SET NUMERIC_ARITHABORT ON is set as default connection option, this SELECT statement will encounter error 1934 and an exception will occur:

Exception 4 <servername> DatabaseMail - DatabaseMail - Id<ProcessId> <NTUserName> <SPID> <StartTime> 1934 msdb <LoginSid> <SessionLoginName> SELECT failed because the following SET options have incorrect settings:  
'NUMERIC_ROUNDABORT'.  
Verify that SET options are correct for use with indexed views and/or indexes on computed columns and/or filtered indexes and/or query notifications and/or XML data type methods and/or spatialindex operations.

當DatabaseMail.exe遇到例外狀況時,會嘗試復原但失敗。 例外狀況會導致交易超出範圍。 基於這個理由, 交易不再有效的 訊息會記錄在 Database Mail 記錄檔中。

不過,問題的根本原因是錯誤 1934 是在 語句中使用 SELECT XML 數據類型方法 (MailRequest.Properties.value('(MailItemId)[1]', 'int')) 時,因為 SET 選項不相容

確認錯誤訊息

  • 檢查 Database Mail 記錄檔中的錯誤訊息是否相同(交易無效)。

  • 藉由啟用語句層級事件、錯誤和警告和 Broker 事件,以收集分析工具追蹤。

  • 檢查 SQL Server 實例設定,以取得預設連線選項。 若要這樣做,請開啟 [SQL Server Management Studio],以滑鼠右鍵按兩下 [伺服器],然後選取 [屬性>連線>] [預設連接選項>] 數值捨入中止。

解決方法

若要解決此問題,請將默認連線選項變更為 SET NUMERIC_ROUNDABORT OFF