Microsoft go-mssqldb driver para SQL Server

O go-mssqldb driver é o driver oficial do Microsoft Go para Microsoft SQL. É uma implementação puramente Go do protocolo TDS (Tabular Data Stream) que utiliza a interface padrão database/sql . Não requer ODBC nem outras bibliotecas C.

O driver liga aplicações Go a todas as versões suportadas da base de dados SQL Server, Base de Dados SQL do Azure, Azure SQL Managed Instance, SQL em Fabric, Fabric Data Warehouse e Azure Synapse Analytics no Windows, Linux e macOS.

Escolhe o teu ponto de partida

Linha de base de produção para o SQL do Azure

Use este exemplo como ponto de partida para uma ligação SQL do Azure orientada à produção. Combina identidade gerida, definições explícitas de TLS, definições limitadas do pool, tempos limite no âmbito do pedido, lógica de repetição transitória com variação aleatória e registos estruturados.

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
	}
}

Este exemplo requer as variáveis de ambiente SQL_SERVER e SQL_DATABASE.

Variáveis opcionais do ambiente:

  • SQL_FEDAUTH (predefinido: ActiveDirectoryManagedIdentity)
  • SQL_APP_NAME (predefinido: go-mssqldb-example)
  • SQL_STARTUP_TIMEOUT (por defeito: 30s, analisado com time.ParseDuration)

Para obter mais informações sobre cada parte deste exemplo, consulte Base de Dados SQL do Azure, Agrupamento de ligações, Tratamento de erros e padrões de repetição e Registo e diagnóstico.

Principais características

  • Go puro: Não requer CGo nem dependências externas em C.
  • Três formatos de cadeia de ligação: URL (sqlserver://), ADO (key=value) e ODBC (odbc:key=value).
  • Autenticação do Microsoft Entra ID: Vários tipos de credenciais através do pacote azuread, incluindo identidade gerida, entidade de serviço e identidade de carga de trabalho.
  • SQL Server e Windows authentication: Suporta autenticação SQL, NTLM, Kerberos e single log-on (SSO) no Windows.
  • Always Encrypted: Encriptação do lado do cliente com certificados locais, Windows Certificate Store e Azure Key Vault.
  • Cópia em massa: Operações de inserção em massa de alto desempenho.
  • Parâmetros com valor de tabela (TVP): Permitem passar dados estruturados para procedimentos armazenados.
  • Vários protocolos: TCP, pipes com nome, memória partilhada e Ligação de Administrador Dedicada (DAC).
  • Encriptação TDS 8.0: Encriptação de ponta a ponta com modo estrito.

Introdução

Artigo Description
Instalação e requisitos do sistema Instala o módulo de drivers e verifica o teu ambiente Go.
Início Rápido: Ligue e consulte Ligue-se a uma instância local ou teste SQL Server e execute a sua primeira consulta em minutos.
Migrar a partir de outros controladores Migra de lib/pq, pgx ou go-sql-driver/mysql para go-mssqldb.

Configurar ligações

Artigo Description
Cadeias de ligação Formatos de cadeias de ligação URL, ADO e ODBC com exemplos.
Opções de ligação Tempos limite, tamanho do pacote, ativação pós-falha, SessionInitSQL e NewConnector.
Encriptação e certificados Modos de encriptação TLS, validação de certificados e TDS 8.0.
Autenticação do SQL Server e do Windows Autenticação SQL, NTLM, Kerberos e configuração SSO.
Autenticação do Microsoft Entra ID Opções de ligação ao Microsoft Entra ID, fluxos de credenciais e exemplos de fornecedores de tokens.
Práticas recomendadas de segurança Prevenção de injeção SQL, gestão de segredos, encriptação e privilégio mínimo.

Trabalhar com dados

Artigo Description
Mapeamentos de tipo de dados Tabela de conversão de tipos de Go para SQL e tipos específicos do driver.
Consultas e instruções Consultas parametrizadas, Exec, Query, QueryRow, e múltiplos conjuntos de resultados.
Transações Níveis de isolamento, pontos de salvaguarda, deteção de deadlocks e padrões de repetição.
Tratamento de erros e padrões de repetição Estrutura de erro do SQL Server, deteção de erros transitórios e retrocesso exponencial.
Procedimentos armazenados Parâmetros de saída, ReturnStatus, e conjuntos de resultados dos procedimentos.
Operações em massa Inserção em massa de alto desempenho com CopyIn.
Parâmetros com valores de tabela Passar dados estruturados para procedimentos armazenados com mssql.TVP.
Dados JSON e XML Consultar, inserir e transformar dados JSON e XML com FOR JSON, OPENJSON, e FOR XML.
Sempre criptografado Encriptação do lado do cliente com certificado local, o Windows Certificate Store e fornecedores do Azure Key Vault.

Implantar e operar

Artigo Description
Pool de conexões Configure o agrupamento de ligações database/sql.
Programação simultânea Segurança das goroutines, grupos de trabalho, consultas paralelas e encerramento controlado.
Afinação de desempenho Ajuste do pool, tamanho do pacote, declarações preparadas e cópia em massa.
Base de Dados SQL do Azure Autenticação sem palavra-passe, limites de ligação, limitação e gestão de failover.
Troubleshooting Erros comuns, configuração de registo e diagnóstico de certificados.
Testing Padrões de teste de integração e configuração de base de dados de teste.

Guias de plataforma e protocolo

Artigo Description
Linux e macOS Configuração multiplataforma, Kerberos, NTLM e caminhos de certificados.
Protocolos TCP, pipes nomeados, memória partilhada, DAC e SQL Browser.
Registo e diagnóstico Sinalizadores de registo, SetLogger, e SetContextLogger.