我创建使用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)')下执行时。如果触发器在其他锁已被占用的事务下执行,会发生什么情况? –
为了清楚起见,您试图使用一个触发器(或者,也许是一组代码)作为多个表的触发器? –