-- 檢查
SELECT DATABASEPROPERTYEX('YourDB', 'IsBrokerEnabled'); -- 1=已啟用
-- 啟用 (若卡住,重啟資料庫後優先執行此句)
ALTER DATABASE YourDB SET ENABLE_BROKER;
GRANT SUBSCRIBE QUERY NOTIFICATIONS TO [YourAppUser];
-- ⚠️ sa/系統管理員無法授予此權限,必須使用普通資料庫使用者
void Application_Start(object sender, EventArgs e) {
string connStr = ConfigurationManager.ConnectionStrings["AppConn"].ConnectionString;
SqlDependency.Start(connStr);
}
void Application_End(object sender, EventArgs e) {
string connStr = ConfigurationManager.ConnectionStrings["AppConn"].ConnectionString;
SqlDependency.Stop(connStr);
}
private DataSet GetData() {
const string CacheKey = "CityList";
if (HttpRuntime.Cache[CacheKey] != null)
return (DataSet)HttpRuntime.Cache[CacheKey];
var ds = new DataSet();
string connStr = ConfigurationManager.ConnectionStrings["AppConn"].ConnectionString;
using (var conn = new SqlConnection(connStr)) {
// 查詢必須符合嚴格限制:明確列名、兩部分命名、無 *、無聚合、無 UNION 等
string sql = "SELECT CityId, CityName FROM dbo.Tbl_City";
using (var cmd = new SqlCommand(sql, conn)) {
var dep = new SqlCacheDependency(cmd);
using (var adapter = new SqlDataAdapter(cmd)) {
adapter.Fill(ds);
}
HttpRuntime.Cache.Insert(CacheKey, ds, dep);
}
}
return ds;
}
| 現象 | 原因 | 解決 |
|---|---|---|
| 緩存永不失效 | 使用 `sa` 連線,無 `SUBSCRIBE QUERY NOTIFICATIONS` 權限 | 建立專用低權限帳號並授權 |
| 啟用 Broker 卡死 | 資料庫有作用中連線/鎖 | 重啟資料庫 (WITH ROLLBACK IMMEDIATE) 後立即執行啟用 |
| 收到通知但資料未變 | 查詢不符合限制 (如用了 * 或 JOIN),導致無效訂閱 | 重寫查詢符合規範 |
| 開發機正常,部署失效 | 防火牆阻擋 Service Broker 端口 (預設 4022) | 開放端口或配置固定端口 `ALTER DATABASE SET NEW_BROKER` |
程式碼中若出現以下,即為舊版輪詢:
請遷移至 `SqlDependency` + 查詢通知模式。
查詢通知將緩存失效從「主動輪詢」升級為「被動推播」,大幅降低資料庫負載與延遲。關鍵在於:Service Broker 啟用、專用帳號授權、查詢語句合規、應用層正確啟動監聽。掌握這 6 步,即可享受高效、即時的緩存一致性保障。