【发布时间】:2020-10-22 08:31:36
【问题描述】:
我们有一个 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'
它返回当前会话的列表,哪些会话被哪些会话阻止,哪些会话具有与之关联的打开事务。
事实证明,如果我运行不同的更新语句,它会被运行上述存储过程的会话阻塞。但是该会话已经完成,并且正在睡觉。然而,睡眠会话仍然有锁定表的活动事务。
我知道我们正在做连接池,以重用连接,但在我看来,休眠会话永远不应该有与之关联的打开事务:事务必须在会话休眠之前提交。 (好吧,也许并非总是如此,但在这种情况下,我绝对不希望在执行此存储过程后会话中保留任何活动事务)。
但是,无论我做什么,它要么引入新的错误,要么不起作用。 我试图从连接中获取事务并手动提交它,但这给了我一条错误消息,显然世界上只有两个人收到过:
当分配给命令的连接处于挂起的本地事务中时,BeginExecuteNonQuery 要求该命令具有事务。该命令的Transaction属性尚未初始化
在连接上显式调用 close 和 dispose 也不会关闭事务。
我的一位同事说,解决方案是我应该重构我的代码以减少对数据库的调用,虽然他可能有一点,但我仍然认为这是治疗症状而不是根本原因:应该完成后可以在会话中关闭事务。
请问各位,一旦存储过程执行完毕,如何强制关闭 SQL Server 会话中打开的事务?
【问题讨论】:
-
你能在没有等待和异步的情况下使用 command.ExecuteNonQuery() 吗?也许这样就行了。
-
可能不是原因,但你没有处理你的 SqlCommand 对象
-
并非如此。这是一个 API,一切都需要异步。即使你能说服我,团队的其他人也不会咬人。
-
另外,您正在将连接和命令传递给
SqlLogStart- 其中有什么,SqlLogStop中有什么?
标签: c# sql-server session transactions locking