【问题标题】:TSQL logging inside transaction using CLR stored procedure使用 CLR 存储过程在事务内记录 TSQL
【发布时间】:2020-04-17 07:32:57
【问题描述】:

我正在尝试将日志写入事务中的另一个数据库,以便即使事务回滚,日志也将继续存在。我读过this answer 上面写着:

一种可能性是使用 CLR 存储过程进行日志记录。这样就可以在事务外打开自己与数据库的连接,输入并提交日志数据。

所以我使用this article 创建了 CLR 存储过程:

[SqlProcedure]
public static void Voice(SqlString procedureName, SqlInt32 id)
{
    Connection = new SqlConnectionStringBuilder();
    Connection.ContextConnection = true;

    using (TransactionScope transScope = new TransactionScope())
    {                
        using (SqlConnection conn = new SqlConnection(Connection.ToString()))
        {
            conn.Open();                    
            SqlCommand cmdInsert = conn.CreateCommand();
            cmdInsert.CommandText = sql;
            cmdInsert.Parameters.Add("@id", SqlDbType.Int);
            cmdInsert.Parameters[0].Value = id;         
            cmdInsert.Parameters.Add("@procedureName", SqlDbType.NVarChar);
            cmdInsert.Parameters[1].Value = procedureName;
            cmdInsert.ExecuteNonQuery();                
        }
        transScope.Complete();
    }
}

但是,在我在 SQL Server 中执行和回滚存储过程后,数据没有保存:

BEGIN TRAN
    EXEC dbo.SayHelloVoice @id = 1,
                           @procedureName = N'FooProcedure'
ROLLBACK TRAN

我们有三个环境:

  • dev。服务器名称是Q-SQL001
  • test。服务器名称是Q-SQL002
  • prod。服务器名称是Q-SQL003

所以这个 CLR 存储过程应该适用于所有环境。

你能说我做错了什么吗? 任何帮助将不胜感激!

更新:

所以工作版本看起来像这样。非常感谢@Milney

var serverName = string.Empty;
var dbName = string.Empty;
serverName = SqlExecuteScalar("SELECT @@SERVERNAME");
dbName = SqlExecuteScalar("SELECT DB_NAME()");

SqlConnectionStringBuilder sqlConn = new SqlConnectionStringBuilder();
sqlConn.InitialCatalog = dbName;
sqlConn.DataSource = serverName;
sqlConn.IntegratedSecurity = true;
sqlConn.ContextConnection = false;
sqlConn.Enlist = false;
sqlConn.ApplicationName = "New application";

var sql = "USE FooDatabase
           INSERT INTO dbo.MyTable ..."
using (SqlConnection conn2 = new SqlConnection(sqlConn.ConnectionString))
{
    conn2.Open();                    
    SqlCommand cmdInsert = conn2.CreateCommand();
    cmdInsert.CommandText = sql;
    cmdInsert.Parameters.Add("@id", SqlDbType.Int);
    cmdInsert.Parameters[0].Value = storeTime;
    cmdInsert.Parameters.Add("@messageText", SqlDbType.NVarChar);
    cmdInsert.Parameters[1].Value = messageText;            
    cmdInsert.ExecuteNonQuery();                    
} 

【问题讨论】:

标签: c# sql-server tsql sql-server-2016 clrstoredprocedure


【解决方案1】:

如果你使用:

Connection.ContextConnection = true;

然后它将使用运行 CLR Sproc 的同一连接 - 您需要打开一个连接。

【讨论】:

  • 是的,但是您的连接被定义为上下文连接,因此它实际上并没有打开新连接,而是“连接”到现有连接
  • 你想做 Connection.ContextConnection = false,并使用相同的连接字符串 var connection = new Connection(Connection.ConnectionString)
  • 然后用你的新代码更新。听起来您实际上没有指定正确的连接字符串...
  • 既然是新连接,就得给它完整的连接字符串
  • 你可以先打开一个上下文连接,然后用 (SELECT @@SERVERNAME and SELECT DB_NAME()) 获取服务器和数据库名称,然后用它们打开第二个连接?
猜你喜欢
  • 2010-09-08
  • 2011-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多