SqlConnection代表與 SQL Server、Azure SQL 或其他支援的 SQL Server 相容端點的邏輯連線。 開啟物件時,若連線集區中有可用的連線,便會從中取得實體連線。 關閉或處理後,該實體連接會回到池中。
使用生命週期短的 SqlConnection 物件來處理工作單位。 不要讓應用程式的單一全域連線持續開啟。
建立連線配置
從應用程式的設定系統載入連線字串。 當程式碼需要驗證或新增設定時,請使用 SqlConnectionStringBuilder :
string configuredConnectionString =
configuration.GetConnectionString("Orders")
?? throw new InvalidOperationException(
"Connection string 'Orders' wasn't configured.");
var builder = new SqlConnectionStringBuilder(configuredConnectionString)
{
ApplicationName = "Orders.Api",
};
從 builder.ConnectionString建立 SqlConnection 。 不要把使用者輸入串接到字串裡。 關於認證模式、安全儲存與語法,請參見 連線字串。
開啟及釋放連線
在同步程式碼中呼叫 Open,或在非同步程式碼中呼叫 OpenAsync。 為每個獨立操作開啟一個新的邏輯連線:
public static async Task<string?> LoadOrderStatusAsync(
string connectionString,
int orderId,
CancellationToken cancellationToken)
{
await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync(cancellationToken);
const string sql = """
SELECT Status
FROM Sales.Orders
WHERE OrderId = @orderId;
""";
using var command =
new SqlCommand(sql, connection) { CommandTimeout = 30 };
command.Parameters.Add(
new SqlParameter("@orderId", SqlDbType.Int) { Value = orderId });
object? value =
await command.ExecuteScalarAsync(cancellationToken);
return value is null or DBNull ? null : (string)value;
}
await using該語句會在成功、錯誤或取消時決定連結。 啟用池化時,處理系統通常會重置並返回實體連線,而非關閉其網路插槽。
應先釋放讀取器和命令,再釋放擁有它們的連線。 不要依賴垃圾回收或終結器來將連線回池。
使用非同步 API
在網路伺服器、服務、使用者介面及工作者中,使用非同步呼叫進行網路綁定的資料庫工作:
OpenAsync(cancellationToken)ExecuteNonQueryAsync(cancellationToken)ExecuteReaderAsync(cancellationToken)ExecuteScalarAsync(cancellationToken)ReadAsync(cancellationToken)
你不需要 Asynchronous Processing=true。 Microsoft.Data.SqlClient 4.0 及後續版本不支援該連接字串關鍵字。
在目前非同步操作結束前,不要對連線、指令或讀取器啟動另一個操作。
套用取消與逾時設定
在每一次非同步資料庫呼叫中傳遞呼叫端的 CancellationToken。 取消要求提供者停止待完成的工作,但完成並不保證會立即完成。 繼續使用設有限制的連線和命令逾時設定。
這些控制有不同的範圍:
| 管理 | Scope |
|---|---|
Connect Timeout |
連線建立或等待共用連線 |
SqlCommand.CommandTimeout |
一指令執行 |
CancellationToken |
來電者請求取消非同步操作 |
逾時或取消並不能證明伺服器已回滾該項操作。 當多個變更必須作為一個單位提交或回滾時,使用交易,並根據操作的冪性與交易結果做出重試決策。
了解連線狀態
State 屬性會傳回 ConnectionState 列舉的快照。
| State | Meaning |
|---|---|
Closed |
邏輯連結並不開放。 |
Connecting |
一場公開行動正在進行中。 |
Open |
邏輯上的連結是開放的。 |
不要在每次指令前用 State 來做健康檢查。 網路在任何檢查後都可能故障。 執行操作並處理產生的例外。
驅動程式通常會回報從關閉到開啟以及從開啟到關閉的轉換。 不要將觀察到的 Executing、Fetching 或 Broken 視為應用程式生命週期階段。
StateChange 事件會回報狀態轉換。 InfoMessage 事件會報告資訊性訊息和伺服器警告,但不會演變成例外狀況。 這些事件應該用來做診斷,而不是協調同時進行的工作。
不要同時分享連線
SqlConnection、SqlCommandSqlDataReaderSqlTransaction不支援多個執行緒同時使用。 讓每個並行操作各自使用自己的連線,並讓連線集區重複使用實體連線。
多重主動結果集(MARS)允許在支援的情境下,在同一連線上同時有多個主動批次。 它不會讓 SqlClient 物件成為執行緒安全,並且新增了會話和交易規則。 除非有特定操作需要,否則就保持關閉。
不要在相依性注入中將開放泛型 SqlConnection 註冊為單一實例。 註冊連線字串、不可變的選項物件,或可建立新連線的工廠。
審慎使用交易
本地交易屬於其連線。 交易中的每個指令都必須使用該連線並設定其 Transaction 屬性。
await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlTransaction transaction =
(SqlTransaction)await connection.BeginTransactionAsync(cancellationToken);
using var command = new SqlCommand(sql, connection, transaction);
command.Parameters.Add(
new SqlParameter("@value", SqlDbType.Int) { Value = value });
await command.ExecuteNonQueryAsync(cancellationToken);
await transaction.CommitAsync(cancellationToken);
如果操作在 CommitAsync 之前失敗,釋放交易就會將交易回滾。 保持交易簡潔。 不要在資料庫交易還保留鎖時進行網路呼叫、使用者互動或無關的運算。
當 System.Transactions.Transaction.Current 啟用時,Open 和 OpenAsync 預設會自動加入。 僅在操作必須保持在環境交易之外時才設定 Enlist=false 。
測量一個邏輯連結
將 StatisticsEnabled 設為 true,以收集單一 SqlConnection 物件的提供者統計資料:
await using var connection = new SqlConnection(connectionString)
{
StatisticsEnabled = true,
};
await connection.OpenAsync(cancellationToken);
connection.ResetStatistics();
using var command = new SqlCommand(sql, connection);
await command.ExecuteNonQueryAsync(cancellationToken);
System.Collections.IDictionary statistics =
connection.RetrieveStatistics();
long roundTrips =
Convert.ToInt64(statistics["ServerRoundtrips"]);
RetrieveStatistics 回傳快照。
ResetStatistics 開始新的測量邊界。 已設定 StatisticsEnabled=false 停止收集;目前收集的價值仍可查詢。 統計是針對連線物件設定的,且會增加開銷,因此應啟用用於針對性診斷,而非每次生產請求。
如需取得整個處理序範圍內的連線集區與連線計量資料,請使用 SqlClient 診斷計數器。
處理連線失敗
在可記錄、轉譯或重試失敗作業的邊界處捕捉 SqlException。 紀錄:
NumberStateClassClientConnectionId- 操作名稱以及已設定的伺服器與資料庫識別碼
不要記錄連線字串、密碼、用戶端密碼或存取權杖。
釋放中斷的連線。 池子偵測到無效的實體連線時會移除它們。 如果憑證、憑證、憑證、DNS 目標或伺服器有變更,請在重試前先修正設定。
僅對暫態故障使用有界重試邏輯。 初始開啟重試、閒置連線恢復與指令重試是不同的機制。 請參考 可設定重試邏輯。