我需要为第三方产品实施分布式事务。我有两个SQL Server和两个SQLCLR触发器。我想从第二个触发器上下文访问本地临时表值,该第二个触发器上下文位于另一个实例上。有可能吗?
//Server 1
[Microsoft.SqlServer.Server.SqlTrigger (Name="SqlTrigger1", Target="Table1", Event="FOR INSERT")]
public static void SqlTrigger1 ()
{
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
conn.Open();
// Create #Temp table
// Insert some data
// Fire trigger Server 2 via Dblink
}
}
//Server 2
[Microsoft.SqlServer.Server.SqlTrigger (Name="SqlTrigger1", Target="Table1", Event="FOR INSERT")]
public static void SqlTrigger2 ()
{
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
conn.Open();
Read #Temp table ???
}
}
答案 0 :(得分:1)
直接答案与SQLCLR无关。从概念上讲,跨实例访问本地临时表(或存储过程)是不可能的,因为与任何其他对象一样,它们是创建它们的实例的本地对象。使用链接服务器时,无法访问调用会话,因此服务器2上运行的代码永远无法访问服务器1上本地临时表的引用。
此外,尽管至少可以访问实例之间的全局临时表(因为这些对所有会话都可见),但仍然需要在服务器2上创建指向服务器1的其他链接服务器,因为这是全局临时表存在的地方。这有点混乱,并没有提供优于创建真实表的优势(除非您创建全局临时表以包含新创建的GUID值作为其名称的一部分,但是您仍然需要传输 值为服务器2,以便构建正确的引用回服务器1,这需要在动态SQL中进行。
来自O.P。的澄清:
当用户调用查询
insert into dbo.Account (Name) values('something')
时,我使用clr触发器拦截它并在server2insert into Server2.dbo.Account (Name) values('something')
上执行相同的查询,我需要在此事务中共享上下文,例如guid变量。
实例之间没有“碎片上下文”这样的东西。无论两个地方需要什么数据和/或值,都需要传递到远程实例中。在这种情况下,您可以将数据打包为NVARCHAR(MAX)
变量中的XML,并在服务器2上执行存储过程,传入NVARCHAR(MAX)
值,将其转换为XML
存储过程,并使用.nodes()
将其解压缩。然后,您还可以将单个标量值作为其他参数传递给远程存储过程。例如:
DECLARE @DataToTransfer NVARCHAR(MAX),
@SomeGuid UNIQUEIDENTIFIER;
SET @DataToTransfer = (
SELECT *
FROM inserted
FOR XML RAW('row')
);
EXEC [LinkedServerName].[DatabaseName].[SchemaName].[StoredProcedureName]
@Param1 = @DataToTransfer,
@Param2 = @SomeGuid;
上面显示的方法非常有效。我用它将每天数百万行从18个生产服务器传输到单个存档服务器。与尝试通过链接服务器执行直接DML / INSERT
语句相比,调用远程存储过程具有更少的锁定问题。此外,这种方法允许发送数据表(打包为XML)和单个变量值(例如您提到的Guid)。
远程存储过程 - 在上面的示例代码中的EXEC
中引用 - 将在服务器2上本地执行,因此它可以创建一个本地临时表,远程表上的触发器将具有访问权限to,或使用SET CONTEXT_INFO或者,如果使用SQL Server 2016(或更新版本),请使用sp_set_session_context。
另外,您可能已经注意到,这些都与SQLCLR无关。当你不使用SQLCLR触发器/对象的任何好处时,我认为没有理由在SQLCLR中引入额外的复杂性。
答案 1 :(得分:0)
使用本地临时表no,但使用全局临时表(两个符号:##globalTemp
而不是#temp
),您应该可以。话虽如此,这可能不是一个好主意,因为你永远不知道##globalTemp
表是否存在。谁应该创造它?
临时表有两种类型:本地和全局。本地 临时表仅在其创建者期间可见 表格首次连接到SQL Server实例 创建或引用。在删除本地临时表后 用户断开与SQL Server实例的连接。全球临时 表对任何用户和任何连接都可见 创建,并在引用该表的所有用户时删除 断开与SQL Server实例的连接。