這篇論壇文章(賽迪網技術社區)著重介紹了"SQL Server_8525"SQL Server數據庫引擎錯誤的解決方法,更多內容請參考下文:
前段時間筆者在做一個BizTalk Server 2006的項目,使用SQL Adapter時碰到“分布式事務已完成。請將此會話登記到新事務或 NULL 事務中”的錯誤。
筆者使用的操作系統為Windows Server 2003企業版 + SP2。數據庫管理系統使用SQL Server 2005企業版 + SP2。BizTalk Server 使用2006企業版,通過BizTalk生成項向導轉換存儲過程為Xml Schema,在部署的時候由BizTalk SQL Adapter通過指定對應XML Namespace來訪問該存儲過程。BizTalk Server 和 SQL Server 部署在不同的服務器上。各服務器不在Windows域中,配置各台服務器的MSDTC,設置“事務管理器通信”為“不要求進行驗證”。
查了一下MSDN文檔,屬於“MSSQLSERVER_8525”數據庫引擎錯誤。MSDN描述了在什麼樣的情況下會碰到“MSSQLSERVER_8525”錯誤。
將分布式事務處理協調器與 SQL Server 配合使用的編程模型需要應用程序顯式登記到分布式事務或從中脫離出來。
滿足以下四個條件時會出現此錯誤:
1.應用程序已登記到分布式事務中。
2.無論原因如何,該事務已結束(已提交或回滾)。
3.用戶應用程序並未顯式地從分布式事務中脫離或顯式地登記到新的分布式事務中。
4.應用程序嘗試執行任何脫離現有分布式事務或登記到新的分布式事務以外的事務操作,如發出查詢或啟動本地事務。
錯誤狀態 1 在應用程序執行創建本地事務的操作時使用,狀態 2 在應用程序嘗試登記到綁定會話時使用。
MSDN說明了相關用戶操作。應用程序登記到分布式事務中之後,應用程序必須顯式地從分布式事務中脫離或登記到另一個分布式事務中。這樣將從上一個登記的事務中隱式脫離。有關從分布式事務脫離或登記到其中的准確語法,請參見該應用程序的編程接口手冊。
更多的內容可以訪問http://technet.microsoft.com/zh-cn/library/bb326310.ASPx。
BizTalk SQL適配器訪問的SQL Server存儲過程大概的內容描述如下:
通過存儲過程傳入多個參數,更新數據到指定數據表中,然後把操作成功或失敗的結果通過 FOR XML AUTO,ELEMENTS語句返回給SQL適配器。對於數據表的更新操作上同事使用“BEGIN TRAN”來開啟一個事務。問題就出在存儲過程添加的事務上。
在BizTalk項目中,筆者使用了Orchestration來訪問SQL適配器,對於Orchestration的設置為“長期事務”,而訪問SQL適配器的一部分功能塊放在了一個作用域中,對該作用域設置為“原子事務”。對BizTalk應用程序進行部署後出現上面提到的錯誤。
由於存儲過程是同事按SQL 2000的方式來寫的,筆者第一想到的就是使用SQL Server 2005中T-SQL語句新功能——TRY/CATCH塊帶代替。TRY CATCH結構就是類似於C#語言中的那種經典結構。關於TRY/CATCH的使用建議看一下“使用 TRY/CATCH 語句解決 SQL Server 2005 死鎖”。
以下是部分SQL片段:
BEGIN TRY
BEGIN TRANSACTION;
--更新語句
COMMIT TRANSACTION;
SET @ReutrnValue = ''01'';
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION;
END
END CATCH;
在存儲過程的最後返回XML:
SELECT Code AS ReturnValue FROM ManifestStatus Manifest
WHERE Code = @ReutrnValue
FOR XML AUTO,ELEMENTS
結果對於單條數據的處理不會再出現該提示,不過對於並發執行過程中,發現有死鎖回滾現象。可能語句的其它地方寫的有問題。
簡單分析。出現“分布式事務已完成。請將此會話登記到新事務或 NULL 事務中”錯誤是在數據庫這一層處理出現,在BizTalk Server 的業務流程中發起了一個分布式事務,而該分布式事務調用的存儲過程剛好又包含有自己的事務,那該事務就變成了內嵌事務。在出現DeadLock的情況下,會RollBACK所有事務。在網上搜索了一下,在程序調試過程中訪問SQL Server出現該錯誤還是比較常見。