Microsoft go-mssqldb driver para SQL Server

El go-mssqldb controlador es el controlador oficial de Microsoft Go para Microsoft SQL. Es una implementación pura en Go del protocolo TDS (Tabular Data Stream) que utiliza la interfaz estándar database/sql . No requiere ODBC ni otras librerías de C.

El controlador conecta las aplicaciones Go a todas las versiones compatibles de SQL Server, Azure SQL Database, Azure SQL Managed Instance, SQL en Fabric, Fabric Data Warehouse y Azure Synapse Analytics en Windows, Linux y macOS.

Elija el punto de partida.

Línea base de producción para Azure SQL

Utiliza este ejemplo como punto de partida para una conexión Azure SQL orientada a producción. Combina identidad administrada, configuración explícita de TLS, configuración de grupo de conexiones limitado, tiempos de espera en el ámbito de la solicitud, lógica de reintentos transitorios con variación aleatoria y registro estructurado.

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

Esta muestra espera SQL_SERVER y SQL_DATABASE variables de entorno.

Variables opcionales de entorno:

  • SQL_FEDAUTH (por defecto: ActiveDirectoryManagedIdentity)
  • SQL_APP_NAME (por defecto: go-mssqldb-example)
  • SQL_STARTUP_TIMEOUT (por defecto: 30s, analizado con time.ParseDuration)

Para más información sobre cada parte de esta muestra, consulta Azure SQL Database, Agrupación de conexiones, Patrones de gestión y reintentos de errores, y Registro y diagnóstico.

Características clave

  • Go puro: No se requieren dependencias de CGo ni de C externo.
  • Tres formatos de cadena de conexión: URL (sqlserver://), ADO (key=value) y ODBC (odbc:key=value).
  • Autenticación con Microsoft Entra ID: varios tipos de credenciales a través del azuread paquete, incluidas la identidad administrada, la entidad de servicio y la identidad de carga de trabajo.
  • SQL Server y autenticación de Windows: Soporta autenticación SQL, NTLM, Kerberos y inicio de sesión único (SSO) en Windows.
  • Siempre cifrado: Cifrado en el lado del cliente con proveedores de certificados locales, Windows Certificate Store y Azure Key Vault.
  • Copia masiva: Operaciones de inserción masiva de alto rendimiento.
  • Parámetros con valores de tabla (TVP): Permiten pasar datos estructurados a procedimientos almacenados.
  • Múltiples protocolos: TCP, pipes nombradas, memoria compartida y Dedicated Administrator Connection (DAC).
  • Cifrado TDS 8.0: Cifrado de extremo a extremo con modo estricto.

Primeros pasos

Artículo Description
Instalación y requisitos del sistema Instala el módulo de controladores y verifica tu entorno Go.
Inicio rápido: Conecta y consulta Conéctate a una instancia local o prueba SQL Server y ejecuta tu primera consulta en minutos.
Migración desde otros controladores Migrar de lib/pq, pgx o go-sql-driver/mysql a go-mssqldb.

Configuración de conexiones

Artículo Description
Cadenas de conexión Formatos de cadenas de conexión URL, ADO y ODBC con ejemplos.
Opciones de conexión Tiempos de espera, tamaño del paquete, conmutación por error, SessionInitSQL, y NewConnector.
Cifrado y certificados Modos de cifrado TLS, validación de certificados y TDS 8.0.
SQL Server y autenticación de Windows Autenticación SQL, NTLM, Kerberos y configuración SSO.
Autenticación de Microsoft Entra ID Opciones de conexión de Microsoft Entra ID, flujos de credenciales y ejemplos de proveedores de tokens.
Recomendaciones de seguridad Prevención de inyección SQL, gestión de secretos, cifrado y privilegio mínimo.

Trabajar con datos

Artículo Description
Asignaciones de tipos de datos Tabla de conversión de tipos de Go a SQL y tipos específicos del controlador.
Consultas y sentencias Consultas parametrizadas, Exec, Query, QueryRow, y múltiples conjuntos de resultados.
Transacciones Niveles de aislamiento, puntos de guardado, detección de bloqueos y patrones de reintentos.
Gestión de errores y patrones de reintentos Estructura de errores de SQL Server, detección de errores transitorios y retroceso exponencial.
procedimientos almacenados Parámetros de salida, ReturnStatus, y conjuntos de resultados de procedimientos.
Operaciones masivas Inserción masiva de alto rendimiento con CopyIn.
Parámetros con valores de tabla Pasa datos estructurados a procedimientos almacenados con mssql.TVP.
Datos JSON y XML Consulta, inserta y transforma datos JSON y XML con FOR JSON, OPENJSON, y FOR XML.
Siempre cifrado Cifrado en el lado del cliente con certificados locales, Windows Certificate Store y Azure Key Vault.

Despliegue y operación

Artículo Description
Agrupación de conexiones Configura el pool de database/sql conexiones.
Programación concurrente Seguridad de las goroutines, grupos de trabajadores, consultas paralelas y apagado controlado.
Ajuste del rendimiento Ajuste de grupos, tamaño de paquetes, instrucciones preparadas y copia masiva.
Azure SQL Database Autenticación sin contraseña, límites de conexión, estrangulamiento y gestión de recuperación ante fallos.
Solución de problemas Errores comunes, configuración de registro y diagnósticos de certificados.
Pruebas: Patrones de pruebas de integración y configuración de bases de datos de prueba.

Guías de plataforma y protocolo

Artículo Description
Linux y macOS Configuración multiplataforma, Kerberos, NTLM y rutas de certificados.
Protocolos TCP, canalizaciones con nombre, memoria compartida, DAC y Explorador de SQL.
Registro y diagnóstico Indicadores de registro, SetLogger, y SetContextLogger.