繁体   English   中英

关闭 SqlConnection 不会关闭 SQL 上的关闭事务

[英]Closing a SqlConnection does not close the close the transaction on SQL

我们有一个 Azure 数据库的数据访问层:

public async Task ExecuteStoredProcedure(string connectionName, string statementText, object parameters)
{
        using (var conn = GetConnection(connectionName))
        {
            await DataActions.ExecuteStoredProcedure(conn, this as IQueryTimeoutReader, statementText, parameters);
            conn.Close();
            conn.Dispose();
        }           
}


internal async static Task ExecuteStoredProcedure(SqlConnection connection, IQueryTimeoutReader timeoutReader, string statementText, object parameters) 
{
        var command = connection.CreateCommand();            
        command.CommandText = statementText;
        command.CommandType = CommandType.StoredProcedure;

        if (timeoutReader != null)
        {
            command.CommandTimeout = timeoutReader.ReadAndResetTimeout();
        }

        ObjectToSqlParameters(parameters, command.Parameters);

        Stopwatch sw = SqlLogStart(connection, command);
        await command.ExecuteNonQueryAsync();
        SqlLogStop(sw, 0);
}

我正在执行一个相当直接的查询:

CREATE OR ALTER PROCEDURE [dbo].[UpdatePartyAccessHistory]
    @UserID uniqueidentifier,
    @PartyID uniqueidentifier
AS
    IF (SELECT COUNT(1) FROM [PartyAccessHistory] 
        WHERE [UserID] = @UserID AND [PartyID] = @PartyID) = 0
    BEGIN
        INSERT INTO [PartyAccessHistory] ([PartyAccessHistoryID], [UserID], [PartyID], [LastAccessedDate])
            SELECT NEWID(), @UserID, @PartyID, GETDATE()
    END 
    ELSE
    BEGIN 
        UPDATE [PartyAccessHistory] 
        SET [LastAccessedDate] = GETDATE()
        WHERE [UserID] = @UserID AND [PartyID] = @PartyID
    END

我遇到的症状是:上面显示的存储过程会立即执行,但随后会锁定表几秒钟。

我有以下查询用于查询数据库:

DECLARE @result TABLE 
                (
                    SPID INT,
                    [Status] VARCHAR(255),
                    Login VARCHAR(255),
                    HostName VARCHAR(255),
                    BlkBy VARCHAR(255),
                    DBName VARCHAR(255),
                    Command VARCHAR(255),
                    CPUTime INT,
                    DiskIO INT,
                    LastBatch VARCHAR(255),
                    ProgramName VARCHAR(255),
                    SPID2 INT,
                    REQUESTID INT
                )

INSERT INTO @result EXEC sp_who2
    SELECT Result.*, [text], Transactions.open_tran 
    FROM @result AS Result
    LEFT JOIN sys.dm_exec_requests der ON der.session_id = Result.SPID 
    OUTER APPLY SYS.dm_exec_sql_text (der.sql_handle) Sql 
    OUTER APPLY sys.dm_exec_query_plan (der.plan_handle) pln 
    LEFT JOIN sys.objects so ON so.object_id = sql.objectid 
    LEFT JOIN sys.sysprocesses AS Transactions ON Transactions.SPID = Result.SPID 

    -- Add any filtering of the results here :
    WHERE ProgramName = 'CRM-Program'  
      AND DBName = 'CRM'

它返回当前会话的列表,哪些会话被哪些会话阻止,哪些会话具有与之关联的打开事务。

事实证明,如果我运行不同的更新语句,它会被运行上述存储过程的 session 阻止。 但是那个 session 已经完成了,并且正在睡觉。 然而,休眠的 session 仍然有锁定表的活动事务。

我知道我们正在做连接池,以重用连接,但在我看来,休眠的 session 永远不应该有与之关联的打开事务:事务必须在 session 睡眠之前提交。 (好吧,也许并非总是如此,但在这种情况下,我绝对不希望在执行此存储过程后 session 上保留任何活动事务)。

但是,无论我做什么,它要么引入新的错误,要么不起作用。 我试图从连接中获取事务并手动提交它,但这给了我一条错误消息,显然世界上只有两个人收到过:

当分配给命令的连接处于挂起的本地事务中时,BeginExecuteNonQuery 要求该命令具有事务。 该命令的 Transaction 属性尚未初始化

在连接上显式调用 close 和 dispose 也不会关闭事务。

我的一位同事说解决方案是我应该重构我的代码以减少对数据库的调用,虽然他可能有一点,但我仍然认为这是治疗症状而不是根本原因:应该有办法完成后关闭 session 上的事务。

拜托,任何人,一旦执行存储过程,如何强制关闭 SQL 服务器 session 上的打开事务?

感谢大家到目前为止的帮助。

问题是,应用程序调用 API 来更新表,然后立即从同一个表再次调用 select - 连接到其他表。 我同事的理论是,这就是导致锁定的原因。 他认为 select 是在与更新相同的事务中执行的(这对我来说没有意义,因为这发生在不同的线程上),这就是锁定表的原因(这对我来说也没有意义,因为即使 select 语句在与更新相同的事务上运行 - 两者都成功执行,所以没有理由让事务保持打开并继续锁定表)

无论如何 - 我们将重构代码。 他希望我们在启动时只调用一次 select sp,然后在客户端维护列表,而不是每次都从数据库中选择它。 这不会没有自己的挑战,但希望这将解决问题。 因为,我仍然认为它只是治标不治本,但在这个阶段我已经尝试了我能想到的所有可能的方法来控制交易并关闭它,但没有任何效果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM