SqlDependency 启动前必须启用 Service Broker,否则静默失败;连接字符串需含 Application Name,SQL 查询须单表且字段显式指定;OnChange 回调需线程安全处理并手动重注册监听。

SqlDependency 启动前必须开启 Service Broker
不启用 Service Broker,SqlDependency 会静默失败——连异常都不抛,只在 OnChange 回调里收到 null 或状态为 Invalid。这是最常卡住人的第一步。
- 检查是否启用:
SELECT is_broker_enabled FROM sys.databases WHERE name = 'YourDBName',返回0就得开 - 启用命令(需 DB owner 权限):
ALTER DATABASE YourDBName SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE - 注意:如果数据库正在被使用,
WITH ROLLBACK IMMEDIATE会强制断开现有连接;生产环境建议选维护窗口执行 - 重启 SQL Server 服务不会自动恢复 Broker 状态,改完必须显式验证
SqlConnection 和 SqlCommand 必须满足严格约束
SqlDependency 不是普通查询的“增强插件”,它对 SQL 语句结构、连接配置极其敏感。稍有偏差,依赖就注册失败,且错误提示极不友好。
- 连接字符串必须包含
Application Name(哪怕只是占位符),例如:"...;Application Name=MyApp;" - SQL 查询必须是单表、无子查询、无聚合函数、无
TOP、无ORDER BY(除非带OFFSET)、字段名必须显式写出(不能用*) - 必须用
SqlCommand的Notification相关属性:调用SqlCommand.Notification = null前先确保SqlDependency.Start()已成功执行 - 示例合规语句:
SELECT Id, Name, UpdatedAt FROM dbo.Users WHERE IsActive = 1
OnChange 回调不是线程安全的,也不能直接更新 UI
回调由 SQL Server 的 Service Broker 消息触发,在任意线程上执行,且可能并发调用。直接在里面操作 WinForms 控件或 WPF Dispatcher,大概率崩溃或丢事件。
- 回调中第一件事应该是检查
args.Type == SqlNotificationType.Change且args.Source == SqlNotificationSource.Table,否则忽略 - 不要在回调里做耗时操作(如查库、发 HTTP 请求),否则会阻塞后续通知
- WinForms:用
this.Invoke(...)或BeginInvoke跳回 UI 线程;WPF:用Dispatcher.BeginInvoke(...) - 每次回调后,必须重新执行
command.ExecuteReader()+dependency.Start()才能继续监听——这不是自动续订
SqlDependency.Stop() 必须配对调用,且不能跨 AppDomain
没调 Stop(),进程退出时可能残留 Service Broker 队列和会话,下次启动再 Start() 就报错:The queue 'SqlQueryNotificationService-xxx' already exists.
-
SqlDependency.Start()是静态方法,全局只应调用一次;Stop()也必须对应调用一次,通常放在应用关闭逻辑里(如AppDomain.CurrentDomain.ProcessExit) - 如果用了多个数据库实例,
Start()和Stop()的连接字符串必须完全一致(包括大小写、空格),否则视为不同实例,Stop()无效 - .NET Core / .NET 5+ 中
SqlDependency仍可用,但不支持 Linux 上的 SQL Server(因依赖 Windows 本地消息队列机制)
Service Broker 的消息延迟不可控,从数据变更到收到通知,通常在 1–3 秒;别把它当实时推送用。真要低延迟,得换 Change Tracking + 轮询,或者直接接 CDC 流。











