【问题标题】:SQL Trigger fails when calling a stored procedure which uses CLR调用使用 CLR 的存储过程时 SQL 触发器失败
【发布时间】:2017-12-01 11:40:18
【问题描述】:

我在同一个 SQL Server 实例上有两个数据库

在“DatabaseA”中,我有一个存储过程,它调用 C# 代码(SQL 中的 CLR 程序集)来解压数据,并在解压后将解压后的数据写入 DatabaseB 的表(ScanTracking、Strings、Numerics)

手动执行的存储过程工作得很好。

但是,当我通过触发器在 DatabaseA 中存在的表上运行存储过程时。我收到以下错误

'事务上下文被另一个会话使用'

错误的完整细节如下:

Msg 6522, Level 16, State 1, Procedure ExecuteDeSerializeBulk, Line 0
A .NET Framework error occurred during execution of user-defined routine or aggregate "ExecuteDeSerializeBulk": 
System.Data.SqlClient.SqlException: Transaction context in use by another session.
System.Data.SqlClient.SqlException: 
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest)
   at System.Data.SqlClient.SqlInternalConnectionTds.PropagateTransactionCookie(Byte[] cookie)
   at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
   at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
   at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
   at System.Data.ProviderBase.DbConnectionPool.PrepareConnection(DbConnection owningObject, DbConnectionInternal obj, Transaction transaction)
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnecti...
The statement has been terminated.

我做了一些研究,发现了以下链接

Transaction context in use by another session

https://learningintheopen.org/2014/01/21/technical-microsoft-sql-server-transact-sql-linked-server-error-transaction-context-in-use-by-another-session-msg-3910-level-16-state-2-line-1/

我没有使用链接服务器或任何复杂的东西,我的两个数据库都在同一台服务器上。

作为一种解决方法,我恢复为每 5 分钟运行一次的 SQL 代理作业,并将数据解压到 DatabaseB 上,这工作正常。但是我的想法告诉我,我没有找到触发器问题的解决方案,也没有使用 SQL 代理作业解决它。

任何想法或建议都会有很大帮助。

【问题讨论】:

  • 是否启用了调用触发器 MARS 的会话?你在使用 TransactionScope 吗?
  • @mjwills - 谢谢我为你更新了问题。如果您现在可以通过完整的异常详细信息了解更多信息,请告诉我。顺便说一句,很好的比喻。我期待您自己的建议。
  • 请向我们展示ExecuteDeSerializeBulk 的源代码、触发器和更新数据库的 C# 代码(因此“触发触发器”)。

标签: c# sql-server stored-procedures triggers sqlclr


【解决方案1】:

手动执行的存储过程可以正常工作。

尝试先执行BEGIN TRAN;,然后在测试时运行存储过程。它会出错吗?它应该得到与从触发器执行它时看到的相同的错误。触发器在系统启动的事务中执行,因此您所描述的内容是有道理的。

这里有一些事情可以尝试:

  1. 与其连接到数据库写入任何内容,不如将值返回给调用进程,然后从那里进行写入。如果可能的话,这是您的最佳选择,因为它可以解耦依赖关系,并让您更灵活地选择如何/何时/何地使用 SQLCLR 代码。

  2. 使用Context Connection = true; 作为连接字符串

  3. 在连接字符串中指定enlist=false;,以不使用尝试附加到现有事务的默认行为。

【讨论】:

  • 感谢您的评论。我添加了 Begin Tran;在执行存储过程之前,我仍然得到同样的错误。我的 CLR 确实将结果返回给调用 sql 存储过程,然后存储过程写回 DatabaseB。
  • @Abe 是的,当运行 proc 本身的测试没有出现错误时,您应该在使用 BEGIN TRAN 时开始收到错误,因为它模拟了运行该 proc 时发生的情况触发器内。即使你已经在做#1(从问题的描述中不清楚),那么第 2 和第 3 项呢?您没有在问题中准确显示您的连接方式。该错误消息表明一个外部连接正试图在当前事务中登记。做 2 或 3 应该可以解决这个问题。
  • @Abe 另外,如果 SQLCLR 对象返回要写入的值,为什么它首先连接到数据库?为了获得解包的价值?或者是传入并正在执行其他操作?
  • 感谢您的 cmets。 CLR 是用 C# 编写的,用于反序列化数据,即解包。 SQL SP 获取原始输出 - 调用 CLR - CLR 反序列化并将反序列化的数据返回给 SQL - SQL 然后对解压缩的数据执行操作。
  • @Abe 好的,感谢您提供的额外信息。不过,您还没有回答有关“为什么 SQLCLR 代码首先连接到数据库/创建SqlConnection”的问题?如果只是解包并返回一个或多个值,为什么需要打开一个连接?并且,您是否尝试过建议 2 和 3?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-12
相关资源
最近更新 更多