是否可以跨链接服务器在SQLCLR触发器之间共享本地临时表?

时间:2016-09-26 17:15:02

标签: sql-server triggers temp-tables linked-server sqlclr

我需要为第三方产品实施分布式事务。我有两个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  ???
         }
    }

2 个答案:

答案 0 :(得分:1)

直接答案与SQLCLR无关。从概念上讲,跨实例访问本地临时表(或存储过程)是不可能的,因为与任何其他对象一样,它们是创建它们的实例的本地对象。使用链接服务器时,无法访问调用会话,因此服务器2上运行的代码永远无法访问服务器1上本地临时表的引用。

此外,尽管至少可以访问实例之间的全局临时表(因为这些对所有会话都可见),但仍然需要在服务器2上创建指向服务器1的其他链接服务器,因为这是全局临时表存在的地方。这有点混乱,并没有提供优于创建真实表的优势(除非您创建全局临时表以包含新创建的GUID值作为其名称的一部分,但是您仍然需要传输 值为服务器2,以便构建正确的引用回服务器1,这需要在动态SQL中进行。

来自O.P。的澄清:

  

当用户调用查询insert into dbo.Account (Name) values('something')时,我使用clr触发器拦截它并在server2 insert 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实例的连接。