該go-mssqldb驅動程式是官方的 Microsoft Go 驅動程式,適用於 Microsoft SQL。 它是純粹 Go 實作的 TDS(Tabular Data Stream)協定,使用標準 database/sql 介面。 它不需要 ODBC 或其他 C 語言函式庫。
此驅動程式可在 Windows、Linux 和 macOS 上,讓 Go 應用程式連線至所有受支援版本的 SQL Server、Azure SQL Database、Azure SQL 受控執行個體、Fabric 中的 SQL 資料庫、Fabric Data Warehouse,以及 Azure Synapse Analytics。
選擇你的起點
- 要在 Windows 上快速執行本地 SQL Server 範例,請從 Quickstart: Connect and query開始。
- 若要使用 Azure SQL 並進行無密碼認證,請先使用 Azure SQL Database 和 Microsoft Entra ID 認證。
- 要從 PostgreSQL 或 MySQL 遷移,請先從 其他驅動程式遷移。
- 若要有效傳輸大量資料,請使用 批量操作 或 表值參數。
- 要排除 TLS、憑證或登入問題,請前往 加密與憑證 及 故障排除頁面。
Azure SQL 的生產環境基準
使用此範例作為生產導向 Azure SQL 連線的起點。 它結合了受管理身份、明確的 TLS 設定、有界池設定、請求範圍逾時、抖動暫態重試邏輯以及結構化日誌。
package main
import (
"context"
"database/sql"
"errors"
"fmt"
"log/slog"
"math/rand"
"net/url"
"os"
"time"
mssql "github.com/microsoft/go-mssqldb"
_ "github.com/microsoft/go-mssqldb/azuread"
)
const (
maxAttempts = 4
baseBackoff = 200 * time.Millisecond
maxBackoff = 3 * time.Second
queryTimeout = 2 * time.Second
startupTimeoutDefault = 30 * time.Second
)
func main() {
baseLogger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
}))
server, ok := getenvRequired("SQL_SERVER")
if !ok {
baseLogger.Error("invalid configuration", "error", "missing SQL_SERVER")
os.Exit(1)
}
database, ok := getenvRequired("SQL_DATABASE")
if !ok {
baseLogger.Error("invalid configuration", "error", "missing SQL_DATABASE")
os.Exit(1)
}
fedAuth := getenvOrDefault("SQL_FEDAUTH", "ActiveDirectoryManagedIdentity")
appName := getenvOrDefault("SQL_APP_NAME", "go-mssqldb-example")
startupTimeout := getenvDurationOrDefault("SQL_STARTUP_TIMEOUT", startupTimeoutDefault)
logger := baseLogger.With(
slog.String("server", server),
slog.String("database", database),
slog.String("fedauth", fedAuth),
slog.String("appName", appName),
)
connString := buildConnString(server, database, appName, fedAuth)
db, err := sql.Open("azuresql", connString)
if err != nil {
logger.Error("open database", "error", err)
os.Exit(1)
}
defer db.Close()
db.SetMaxOpenConns(20)
db.SetMaxIdleConns(10)
db.SetConnMaxIdleTime(2 * time.Minute)
db.SetConnMaxLifetime(5 * time.Minute)
rootCtx := context.Background()
startupCtx, cancel := context.WithTimeout(rootCtx, startupTimeout)
defer cancel()
err = withRetry(startupCtx, logger, func(ctx context.Context) error {
return db.PingContext(ctx)
})
if err != nil {
logger.Error("ping database", "error", err)
os.Exit(1)
}
var databaseName string
err = withRetry(rootCtx, logger, func(ctx context.Context) error {
queryCtx, cancel := context.WithTimeout(ctx, queryTimeout)
defer cancel()
return db.QueryRowContext(queryCtx, "SELECT DB_NAME()").Scan(&databaseName)
})
if err != nil {
logger.Error("query database", "error", err)
os.Exit(1)
}
logger.Info("database ready", "database", databaseName)
}
func withRetry(ctx context.Context, logger *slog.Logger, fn func(context.Context) error) error {
var lastErr error
for attempt := 1; attempt <= maxAttempts; attempt++ {
lastErr = fn(ctx)
if lastErr == nil {
return nil
}
if !isTransient(lastErr) || attempt == maxAttempts {
return lastErr
}
delay := backoffWithJitter(baseBackoff, maxBackoff, attempt)
logger.WarnContext(ctx, "transient SQL error; retrying",
"attempt", attempt,
"delay", delay.String(),
"error", lastErr,
)
timer := time.NewTimer(delay)
select {
case <-ctx.Done():
timer.Stop()
return ctx.Err()
case <-timer.C:
}
}
return lastErr
}
func backoffWithJitter(baseDelay, maxDelay time.Duration, attempt int) time.Duration {
delay := baseDelay * time.Duration(1<<(attempt-1))
if delay > maxDelay {
delay = maxDelay
}
jitterFraction := 0.20
multiplier := (1 - jitterFraction) + rand.Float64()*(2*jitterFraction)
return time.Duration(float64(delay) * multiplier)
}
func buildConnString(server, database, appName, fedAuth string) string {
query := url.Values{
"database": []string{database},
"fedauth": []string{fedAuth},
"encrypt": []string{"true"},
"TrustServerCertificate": []string{"false"},
"app name": []string{appName},
"log": []string{"1"},
}
return fmt.Sprintf("sqlserver://%s?%s", server, query.Encode())
}
func getenvRequired(key string) (string, bool) {
value := os.Getenv(key)
if value == "" {
return "", false
}
return value, true
}
func getenvOrDefault(key, defaultValue string) string {
value, ok := getenvRequired(key)
if !ok {
return defaultValue
}
return value
}
func getenvDurationOrDefault(key string, defaultValue time.Duration) time.Duration {
value := os.Getenv(key)
if value == "" {
return defaultValue
}
parsed, err := time.ParseDuration(value)
if err != nil {
return defaultValue
}
return parsed
}
func isTransient(err error) bool {
var sqlErr mssql.Error
if !errors.As(err, &sqlErr) {
return false
}
switch sqlErr.Number {
case
// Connection-establishment and transport transient errors.
64, 233, 4060, 4221,
10053, 10054,
10928, 10929,
// Azure SQL failover, throttling, and availability errors.
40020, 40143, 40166,
40197, 40501, 40540, 40613,
42108, 42109,
49918, 49919, 49920,
// Common retryable statement-level contention errors.
1205, 1222:
return true
default:
return false
}
}
本範例期望 SQL_SERVER 和 SQL_DATABASE 環境變數。
可選環境變數:
-
SQL_FEDAUTH(預設值:ActiveDirectoryManagedIdentity) -
SQL_APP_NAME(預設值:go-mssqldb-example) -
SQL_STARTUP_TIMEOUT(預設:30s,解析為time.ParseDuration)
欲了解更多本範例各部分的資訊,請參閱 Azure SQL Database、連線池化、錯誤處理與重試模式,以及日誌與診斷。
主要功能
- Pure Go:不需要 CGo 或外部 C 依賴。
-
三種 連接字串 格式:URL (
sqlserver://)、ADO (key=value和 ODBC (odbc:key=value)。 -
Microsoft Entra ID 認證:透過
azuread套件支援多種憑證類型,包括管理身份、服務主體及工作負載身份。 - SQL Server 與 Windows 驗證:支援 SQL 認證、NTLM、Kerberos 及 Windows 上的單一登入(SSO)。
- Always Encrypted:客戶端加密,使用本地憑證、Windows 憑證商店及 Azure Key Vault 金鑰提供者。
- 批量複製:高效能大量插入作業。
- 資料表值參數(TVP):將結構化資料傳遞給預存程序。
- 多種協定:TCP、命名管線、共享記憶體,以及專用管理員連線(DAC)。
- TDS 8.0 加密:端對端加密,採用嚴格模式。
開始
| 文章 | Description |
|---|---|
| 安裝與系統需求 | 安裝驅動模組並確認你的 Go 環境。 |
| 快速入門:連結與查詢 | 連接到本地或測試的 SQL Server 實例,並在幾分鐘內執行你的第一個查詢。 |
| 從其他驅動程式遷移 | 從 lib/pq、pgx 或 go-sql-driver/mysql 遷移到 go-mssqldb。 |
設定連線
| 文章 | Description |
|---|---|
| 連接字串 | URL、ADO 及 ODBC 連接字串 格式及範例。 |
| 連線選項 | 逾時、封包大小、容錯移轉、SessionInitSQL和NewConnector。 |
| 加密與憑證 | TLS 加密模式、憑證驗證及 TDS 8.0。 |
| SQL Server 與 Windows Authentication | SQL 認證、NTLM、Kerberos 和 SSO 設定。 |
| Microsoft Entra ID 驗證 | Microsoft Entra ID 連線選項、憑證流程及令牌提供者範例。 |
| 安全性最佳做法 | SQL 注入防護、秘密管理、加密以及最小特權。 |
處理資料
| 文章 | Description |
|---|---|
| 數據類型對應 | Go 與 SQL 之間的型別轉換表,以及驅動程式特定型別。 |
| 查詢與陳述 | 參數化查詢、 Exec、 Query、 QueryRow及多個結果集。 |
| 交易 | 隔離等級、存檔點、死鎖偵測和重試模式。 |
| 錯誤處理與重試模式 | SQL Server 錯誤結構、暫時錯誤偵測與指數退讓。 |
| 預存程序 | 輸出參數, ReturnStatus以及程序的結果集。 |
| 大量作業 | 使用 CopyIn 進行高效能大量插入。 |
| 資料表值參數 | 將結構化資料傳給儲存程序,使用 mssql.TVP。 |
| JSON 與 XML 資料 | 使用 FOR JSON、OPENJSON 和 FOR XML 查詢、插入及轉換 JSON 和 XML 資料。 |
| 一律加密 | 客戶端加密,使用本地憑證、Windows 憑證儲存庫及 Azure Key Vault 提供者。 |
部署和操作
| 文章 | Description |
|---|---|
| 連接共用 | 設定 database/sql 連線池。 |
| 同時播出節目 | Goroutine 安全、員工池、平行查詢,以及優雅關機。 |
| 性能調校 | 池調校、封包大小、已準備好的報表,以及批量文案。 |
| Azure SQL Database | 無密碼認證、連線限制、限速與故障轉移處理。 |
| Troubleshooting | 常見錯誤、日誌設定與憑證診斷。 |
| Testing | 整合測試模式與測試資料庫設置。 |
平台與協定指南
| 文章 | Description |
|---|---|
| Linux 和 macOS | 跨平台設定、Kerberos、NTLM 及憑證路徑。 |
| 通訊協定 | TCP、命名管線、共享記憶體、DAC 以及 SQL 瀏覽器。 |
| 記錄和診斷 | 記錄旗標、SetLogger 和 SetContextLogger。 |
提出功能要求
要申請功能,請在 go-mssqldb GitHub 倉庫中開啟一個問題。