我創建使用SQL CLR觸發器在Microsoft SQL Server 2012的一個數據庫同步引擎,這些觸發器不調用存儲過程或函數(從而有機會獲得inserted和deleted僞表但無法訪問@@ procid)。SQL CLR觸發器 - 獲取源表
差異here,以供參考。
這種「同步引擎」使用映射表來確定哪些表和字段映射是此同步作業。爲了確定目標表和字段(從我的映射表),我需要從觸發器本身獲取源表名。我在Stack Overflow和其他網站上發現了很多答案,說這是不可能的。但是,我發現一個website,提供了一個線索:
潛在的解決方案:
using (SqlConnection lConnection = new SqlConnection(@"context connection=true")) {
SqlCommand cmd = new SqlCommand("SELECT object_name(resource_associated_entity_id) FROM sys.dm_tran_locks WHERE request_session_id = @@spid and resource_type = 'OBJECT'", lConnection);
cmd.CommandType = CommandType.Text;
var obj = cmd.ExecuteScalar();
}
但這實際上返回正確的表名。
問:
我的問題是,如何可靠是這個潛在的解決方案? @@ spid實際上是否僅限於此單個觸發器執行?或者是否有可能其他同時觸發器會在此進程ID內重疊?它會在數據庫中多次執行相同和/或不同的觸發器嗎?
從這些網站,它似乎的進程ID,其實是限制在打開的連接,不重疊:here,here和here。
這會不會是一種安全的方法,讓我的源表?
爲什麼?
正如我已經注意到了類似的問題,但都沒有對我的具體情況有效的答案(除了一個)。大部分這些網站上的意見,問:「爲什麼?」,爲了搶佔的是,這是爲什麼:
此同步引擎上的單個數據庫上運行並且可將更改到目標表,改造與用戶數據自定義的源到目標類型轉換和解析,甚至可以使用CSharpCodeProvider執行也存儲在這些映射表中的方法來轉換數據。它已經建立,相當強大,並且對我們正在做的事情有很好的性能指標。我現在試圖構建它以允許1:n表更改(包括擴展表需要與「主」表相同的ID),並且試圖「代碼化」代碼。以前每個觸發器都有一個硬編碼的「目標表」定義,我使用映射表來確定源。現在我想獲取源表並使用我的映射表來確定所有的目標表。這用於中等負載環境,並將更改推送到「更改訂單簿」,單獨的服務器進程將採用該更改以完成CRUD操作。
編輯
正如在評論中提到的,上面列出的查詢是相當「前途未卜」。它會經常(例如在SQL Server重新啓動後)返回像syscolpars或sysidxstats這樣的系統對象。但是,似乎在dm_tran_locks表中,總是有一個相關的resource_type爲'RID'(行ID)和相同的object_name。我這工作可靠到目前爲止當前查詢是以下(將更新,如果這變化的情況下高負載測試不工作):如果這是總是如此
select t1.ObjectName FROM (
SELECT object_name(resource_associated_entity_id) as ObjectName
FROM sys.dm_tran_locks WHERE resource_type = 'OBJECT' and request_session_id = @@spid
) t1 inner join (
SELECT OBJECT_NAME(partitions.OBJECT_ID) as ObjectName
FROM sys.dm_tran_locks
INNER JOIN sys.partitions ON partitions.hobt_id = dm_tran_locks.resource_associated_entity_id
WHERE resource_type = 'RID'
) t2 on t1.ObjectName = t2.ObjectName
,我必須找到了在測試期間。
這是可能的。它假設引擎將精確鎖定一個對象,即觸發器執行的表。也許這總是會發生,但你不能指望任何人給你保證。我不太關心「@@ spid」 - 儘管MARS可以讓多個語句在連接上處於活動狀態,但這是一種虛假的併發。觸發器執行不會重疊,它們會按順序執行。你不應該擔心其他陳述干擾。 –
確保測試當您拋出事務時會發生什麼,特別是在'SERIALIZABLE'('SELECT * FROM T WITH(HOLDLOCK)')下執行時。如果觸發器在其他鎖已被佔用的事務下執行,會發生什麼情況? –
爲了清楚起見,您試圖使用一個觸發器(或者,也許是一組代碼)作爲多個表的觸發器? –