含DROP TABLE的代码导致DBCC SHRINKFILE超时阻塞的排查求助
排查DROP TABLE导致DBCC SHRINKFILE阻塞的步骤
检查NHibernate事务的显式提交逻辑
NHibernate默认会为修改类操作(包括DDL如DROP TABLE)启动隐式事务,若任务代码中未显式提交事务,该事务会持续持有锁。- 确认执行
DROP TABLE的代码块是否用using包裹事务并完成提交:using (var session = SessionFactory.OpenSession()) using (var tx = session.BeginTransaction()) { session.CreateSQLQuery("DROP TABLE TargetTable").ExecuteUpdate(); tx.Commit(); // 必须显式提交,否则事务会挂起 } - 排查是否存在
FlushMode设置为Auto或Always导致的隐式事务未提交情况,可在执行DDL后强制调用session.Flush()和事务提交。
- 确认执行
验证Hangfire任务的事务活跃状态
在DROP TABLE执行后、DBCC SHRINKFILE执行前,添加代码查询当前会话的事务状态:- 通过NHibernate API检查:
session.Transaction.IsActive,若返回true说明事务未提交。 - 通过SQL查询系统视图确认:
SELECT t.transaction_id, t.session_id, t.transaction_begin_time FROM sys.dm_tran_session_transactions t JOIN sys.dm_exec_sessions s ON t.session_id = s.session_id WHERE s.program_name LIKE '%Hangfire%' -- 匹配Hangfire的会话标识
对比SSMS执行时的结果,SSMS默认自动提交模式,
DROP TABLE后事务会立即结束。- 通过NHibernate API检查:
分析锁持有情况
当任务执行到DROP TABLE后暂停(可临时加延迟),立即执行以下查询查看锁状态:SELECT request_session_id, resource_type, request_mode, resource_description FROM sys.dm_tran_locks WHERE request_session_id = (SELECT @@SPID FROM [当前Hangfire任务的数据库连接])若存在
SCH_M模式的锁(DROP TABLE会申请该锁)且未释放,说明事务未提交,这会直接阻塞DBCC SHRINKFILE(收缩需要文件级的锁,与SCH_M锁冲突)。排查Hangfire的Session/连接复用问题
确认Hangfire任务是否复用了全局的NHibernate Session或数据库连接:- 若任务使用共享Session,之前的操作可能残留未提交的事务,导致
DROP TABLE被加入同一事务,锁无法释放。 - 确保每个Hangfire任务都创建独立的Session实例,执行完成后显式关闭:
session.Close()或用using自动释放。
- 若任务使用共享Session,之前的操作可能残留未提交的事务,导致
绕过NHibernate事务执行DDL
尝试直接用ADO.NET连接执行DROP TABLE,绕过NHibernate的事务管理,验证是否还会阻塞:using (var conn = new SqlConnection("你的连接字符串")) { conn.Open(); using (var cmd = new SqlCommand("DROP TABLE TargetTable", conn)) { cmd.ExecuteNonQuery(); } }若此方式下
SHRINKFILE不再阻塞,说明问题出在NHibernate的事务管理逻辑上。检查异常处理中的事务回滚
排查任务代码的try-catch块,确保异常发生时事务被正确回滚:using (var session = SessionFactory.OpenSession()) using (var tx = session.BeginTransaction()) { try { session.CreateSQLQuery("DROP TABLE TargetTable").ExecuteUpdate(); // 其他操作 tx.Commit(); } catch (Exception ex) { tx.Rollback(); // 异常时必须回滚,避免事务挂起 throw; } }若异常发生后未回滚,事务会持续持有锁,导致后续
SHRINKFILE阻塞。
内容的提问来源于stack exchange,提问作者Staša Sekulić
相关产品推荐
相关产品推荐

