Migracja do go-mssqldb z innych sterowników

Ten przewodnik pomaga deweloperom Go migrować z PostgreSQL, MySQL i innych sterowników baz danych do go-mssqldb SQL Server. Obejmuje różnice w składni SQL, zmiany specyficzne dla sterowników oraz równoważne wzorce dla typowych operacji.

Note

Przykłady w tym artykule porównane są z przykładową bazą danych AdventureWorks2025 .

Dlaczego migrować do SQL Server z go-mssqldb

Funkcja SQL Server z go-mssqldb
Zabezpieczenia przedsiębiorstwa Zawsze szyfrowane, bezpieczeństwo na poziomie wiersza, dynamiczne maskowanie danych, przezroczyste szyfrowanie danych (TDE).
Authentication Microsoft Entra ID (dawniej Azure AD), zarządzana tożsamość, uwierzytelnianie systemu Windows, Kerberos.
Integracja z platformą Azure Natywna obsługa Azure SQL Database z automatycznym szyfrowaniem, połączeniami bez hasła i obsługą awaryjnej.
Performance indeksy kolumnowe, OLTP w pamięci, magazyn zapytań do automatycznego korygowania planu.
Formaty danych Wbudowane wsparcie dla JSON i XML z indeksowaniem i zapytaniami po stronie serwera.
Tooling SQL Server Management Studio (SSMS), Azure Data Studio, Visual Studio Code SQL extensions.

Lista kontrolna dotycząca migracji

Przejrzyj te elementy, zanim zaczniesz przenosić zapytania linia po linijce:

Rozważenie Co zmienić
Składnia symboli zastępczych różni się od tej używanej w wielu sterownikach Go. Zastąp ?, $1 i podobne symbole zastępcze elementami @name lub @p1, a następnie przekaż argumenty sql.Named(), tam gdzie to odpowiednie.
LastInsertId() nie jest obsługiwany. Użyj polecenia OUTPUT INSERTED.<column> lub SELECT SCOPE_IDENTITY() zamiast tego.
Wartości Go są domyślnie mapowane string na typy Unicode. Spodziewaj się nvarchar semantyki, chyba że wybierzesz specyficzny dla sterownika typ, na przykład mssql.VarChar dla danych niezwiązanych z Unicode.
Tabele tymczasowe mają zakres ograniczony do fizycznego połączenia. Zachowaj logikę tworzenia i używania tabeli tymczasowej w ramach tego samego połączenia lub tej samej transakcji, jeśli późniejsze instrukcje zależą od tej tabeli.
Uwierzytelnianie Microsoft Entra korzysta z innego mechanizmu rejestracji sterownika. Zaimportuj github.com/microsoft/go-mssqldb/azuread, użyj sql.Open("azuresql", ...) i jawnie ustaw opcje TLS usługi Azure SQL za pomocą encrypt=true&TrustServerCertificate=false.

Aby uzyskać głębsze wskazówki dotyczące tych obszarów, zobacz Zapytania i instrukcje, Ograniczenia, mapowania typów danych, uwierzytelnianie Microsoft Entra ID oraz Rozwiązywanie problemów.

Migracja z lib/pq (PostgreSQL)

Zmień nazwę importu i sterownika

Zastąp lib/pq nazwę importu i sterownika na go-mssqldb:

import _ "github.com/lib/pq"
db, err := sql.Open("postgres", connString)

// After (SQL Server with go-mssqldb):
import _ "github.com/microsoft/go-mssqldb"
db, err := sql.Open("sqlserver", connString)

Zmień format parametrów połączenia

Przekonwertowanie formatu klucz-wartość PostgreSQL na adres URL SQL Server:

// lib/pq connection string:
"host=<server> port=5432 user=<user> password=<password> dbname=AdventureWorks2025 sslmode=require"

// go-mssqldb connection string:
"sqlserver://<user>:<password>@<server>:1433?database=AdventureWorks2025&encrypt=true"

Zmień symbole zastępcze parametrów

PostgreSQL używa pozycyjnych symboli zastępczych $1, $2. SQL Server używa parametrów nazwanych z @:

// PostgreSQL (lib/pq):
db.QueryContext(ctx, "SELECT * FROM users WHERE id = $1 AND status = $2", id, status)

// SQL Server (go-mssqldb):
db.QueryContext(ctx, "SELECT ProductID, Name FROM Production.Product WHERE ProductID = @id AND Color = @color",
    sql.Named("id", id),
    sql.Named("color", color))

Zmiany składni SQL

Operation PostgreSQL SQL Server
Automatyczne inkrementowanie SERIAL lub GENERATED ALWAYS AS IDENTITY IDENTITY(1,1)
Pobierz wstawione ID RETURNING id OUTPUT INSERTED.id lub SELECT SCOPE_IDENTITY()
Typ boolowski BOOLEAN BIT
Konkatenacja ciągów znaków \|\| + lub CONCAT()
Bieżący znacznik czasu NOW() lub CURRENT_TIMESTAMP GETUTCDATE() lub SYSDATETIMEOFFSET()
Ogranicz liczbę wierszy LIMIT 10 OFFSET 20 OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
Typ ciągu TEXT lub VARCHAR NVARCHAR(MAX) lub NVARCHAR(n)
Ekstrakcja JSON column->>'key' JSON_VALUE(column, '$.key')
Upsert INSERT ... ON CONFLICT DO UPDATE MERGE, oświadczenie
Typ tablicy INTEGER[] Brak natywnych macierzy. Używaj parametrów tabelowych.
Uwzględnij wielkość liter Domyślnie wrażliwe na wielka litera Domyślnie nie rozróżnia wielkości liter (zależy od sortowania).

Pobierz wstawiony identyfikator

Zastąp klauzulę RETURNING PostgreSQL klauzulą OUTPUT SQL Server:

var id int
err := db.QueryRowContext(ctx,
    "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id",
    name, email).Scan(&id)

// SQL Server (go-mssqldb) using OUTPUT:
var id int
err := db.QueryRowContext(ctx,
    "INSERT INTO HumanResources.Department (Name, GroupName) OUTPUT INSERTED.DepartmentID VALUES (@name, @groupName)",
    sql.Named("name", name),
    sql.Named("groupName", groupName)).Scan(&id)

Pagination

Zamień składnię LIMIT/OFFSET na składnię OFFSET/FETCH NEXT.

// PostgreSQL:
"SELECT * FROM employees ORDER BY id LIMIT $1 OFFSET $2"

// SQL Server (requires ORDER BY):
"SELECT ProductID, Name, ListPrice FROM Production.Product ORDER BY ProductID OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY"

Migracja z pgx (PostgreSQL)

Sterownik pgx korzysta z własnej puli połączeń i API, które różnią się od .database/sql Aby przeprowadzić migrację, przełącz się na standardowy interfejs database/sql.

Zmiana z puli pgx na bazę danych/SQL

Zamień pgxpool API na standardowy database/sql interfejs.

// Before (pgx):
import "github.com/jackc/pgx/v5/pgxpool"
pool, err := pgxpool.New(ctx, "postgres://user:pass@<server>:5432/AdventureWorks2025")
defer pool.Close()
rows, err := pool.Query(ctx, "SELECT * FROM users WHERE id = $1", id)

// After (go-mssqldb with database/sql):
import (
    "database/sql"
    _ "github.com/microsoft/go-mssqldb"
)
db, err := sql.Open("sqlserver", "sqlserver://user:pass@<server>:1433?database=AdventureWorks2025")
defer db.Close()
rows, err := db.QueryContext(ctx,
    "SELECT ProductID, Name FROM Production.Product WHERE ProductID = @id", sql.Named("id", id))

Zastąp funkcje specyficzne dla pgx

Funkcja PGX Odpowiednik go-mssqldb
pgx.CollectRows Ręczna rows.Next() i rows.Scan() pętla.
pgx.RowToStructByName Manualne rows.Scan przejście do dziedzin konstrukcji.
Zapytania wsadowe (pgx.Batch) Wiele ExecContext wywołań lub procedur przechowywanych.
COPY FROM do wstawiania zbiorczego mssql.CopyIn do wstawiania zbiorczego.
pgx.ConnConfig msdsn.Config lub łańcuchy połączeń oparte na URL.
pgxpool.Pool sql.DB z SetMaxOpenConns i SetMaxIdleConns.

Migracja z go-sql-driver/mysql (MySQL)

Zamień nazwę importu MySQL i sterownika

Zamień import i nazwę sterownika MySQL na go-mssqldb.

// Before (MySQL):
import _ "github.com/go-sql-driver/mysql"
db, err := sql.Open("mysql", connString)

// After (SQL Server):
import _ "github.com/microsoft/go-mssqldb"
db, err := sql.Open("sqlserver", connString)

Przekonwertowanie formatu MySQL DSN

Przekonwertuj format MySQL DSN na adres URL SQL Server.

// MySQL DSN:
"user:password@tcp(<server>:3306)/AdventureWorks2025?tls=true"

// go-mssqldb URL:
"sqlserver://user:password@<server>:1433?database=AdventureWorks2025&encrypt=true"

Zamień zastępcze znaki zapytania

MySQL używa ? symboli zastępczych pozycyjnych.

// MySQL:
db.QueryContext(ctx, "SELECT * FROM users WHERE id = ? AND status = ?", id, status)

// SQL Server:
db.QueryContext(ctx, "SELECT ProductID, Name FROM Production.Product WHERE ProductID = @id AND Color = @color",
    sql.Named("id", id),
    sql.Named("color", color))

Porównaj składnię MySQL i SQL Server

Operation MySQL SQL Server
Automatyczne inkrementowanie AUTO_INCREMENT IDENTITY(1,1)
Pobierz wstawione ID LAST_INSERT_ID() SCOPE_IDENTITY() lub OUTPUT INSERTED.id
Ogranicz liczbę wierszy LIMIT 10 OFFSET 20 OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
Bieżący znacznik czasu NOW() GETUTCDATE()
Jeśli null IFNULL(expr, default) ISNULL(expr, default) lub COALESCE(expr, default)
Długość sznurka LENGTH(str) LEN(str)
Podciąg SUBSTRING(str, start, len) SUBSTRING(str, start, len) (to samo)
Format daty DATE_FORMAT(d, '%Y-%m-%d') FORMAT(d, 'yyyy-MM-dd') lub CONVERT(VARCHAR, d, 23)
Upsert INSERT ... ON DUPLICATE KEY UPDATE MERGE, oświadczenie
Ujmowanie w apostrofy odwrotne `column` [column]

Zastąpienie składni specyficznej dla MySQL

Składnia MySQL Odpowiednik SQL Server
AUTO_INCREMENT IDENTITY(1,1)
LIMIT n OFFSET m OFFSET m ROWS FETCH NEXT n ROWS ONLY (wymaga ORDER BY)

AUTO_INCREMENT do IDENTITY:

-- MySQL:
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100)
);

-- SQL Server:
CREATE TABLE HumanResources.NewDepartment (
    DepartmentID SMALLINT IDENTITY(1,1) PRIMARY KEY,
    Name NVARCHAR(50) NOT NULL
);

LIMIT to OFFSET/FETCH:

-- MySQL:
SELECT * FROM users LIMIT 10 OFFSET 20;

-- SQL Server:
SELECT ProductID, Name, ListPrice
FROM Production.Product
ORDER BY ProductID
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

Typowe wzorce migracji

Pobierz ostatnią wstawioną tożsamość

Użyj klauzuli OUTPUT lub SCOPE_IDENTITY() aby pobrać wartość identyfikacyjną wstawionego wiersza:

// Pattern 1: OUTPUT clause (recommended, works with batch inserts).
var id int64
err := db.QueryRowContext(ctx,
    "INSERT INTO HumanResources.Department (Name, GroupName) OUTPUT INSERTED.DepartmentID VALUES (@name, @groupName)",
    sql.Named("name", "Engineering"),
    sql.Named("groupName", "Research and Development")).Scan(&id)

// Pattern 2: SCOPE_IDENTITY (works with single-row inserts).
var id int64
err := db.QueryRowContext(ctx,
    "INSERT INTO HumanResources.Department (Name, GroupName) VALUES (@name, @groupName); SELECT SCOPE_IDENTITY()",
    sql.Named("name", "Engineering"),
    sql.Named("groupName", "Research and Development")).Scan(&id)

Wskazówka

Wolej zdanie OUTPUT niż SCOPE_IDENTITY(). Klauzula OUTPUT działa z wstawkami wsadowymi i nie zależy od kolejności instrukcji.

Upsert (wstaw lub zaktualizuj)

W PostgreSQL ON CONFLICT i w MySQL ON DUPLICATE KEY UPDATE odpowiadają elementowi MERGE w SQL Server:

_, err := db.ExecContext(ctx, `
    MERGE HumanResources.Department AS target
    USING (SELECT @id AS DepartmentID, @name AS Name, @groupName AS GroupName) AS source
    ON target.DepartmentID = source.DepartmentID
    WHEN MATCHED THEN
        UPDATE SET Name = source.Name, GroupName = source.GroupName, ModifiedDate = GETDATE()
    WHEN NOT MATCHED THEN
        INSERT (Name, GroupName, ModifiedDate) VALUES (source.Name, source.GroupName, GETDATE());`,
    sql.Named("id", dept.ID),
    sql.Named("name", dept.Name),
    sql.Named("groupName", dept.GroupName))

Wstawianie zbiorcze

Zamień PostgreSQL COPY lub MySQL LOAD DATA na mssql.CopyIn.

import mssql "github.com/microsoft/go-mssqldb"

stmt, err := db.Prepare(mssql.CopyIn("HumanResources.Department", mssql.BulkOptions{}, "Name", "GroupName", "ModifiedDate"))
if err != nil {
    return err
}

for _, dept := range departments {
    _, err = stmt.Exec(dept.Name, dept.GroupName, time.Now())
    if err != nil {
        return err
    }
}

// Flush the buffer.
_, err = stmt.Exec()
if err != nil {
    return err
}
stmt.Close()

Obsługa wartości NULL

Wszystkie sterowniki bazy danych Go obsługują wartości NULL w ten sam sposób, ponieważ używają typów database/sql .

var color sql.NullString
err := db.QueryRowContext(ctx,
    "SELECT Color FROM Production.Product WHERE ProductID = @id",
    sql.Named("id", 1)).Scan(&color)

if color.Valid {
    fmt.Println(color.String)
} else {
    fmt.Println("NULL")
}

Transactions

Wszystkie sterowniki bazy danych Go korzystają z tego samego database/sql API transakcyjnego.

tx, err := db.BeginTx(ctx, nil)
if err != nil {
    return err
}
defer tx.Rollback()

_, err = tx.ExecContext(ctx,
    "UPDATE Production.ProductInventory SET Quantity = Quantity - @qty WHERE ProductID = @pid AND LocationID = @fromLoc",
    sql.Named("qty", qty),
    sql.Named("pid", productID),
    sql.Named("fromLoc", fromLocationID))
if err != nil {
    return err
}

_, err = tx.ExecContext(ctx,
    "UPDATE Production.ProductInventory SET Quantity = Quantity + @qty WHERE ProductID = @pid AND LocationID = @toLoc",
    sql.Named("qty", qty),
    sql.Named("pid", productID),
    sql.Named("toLoc", toLocationID))
if err != nil {
    return err
}

return tx.Commit()

Lista kontrolna migracji

Etap Action
Instalowanie sterownika go get github.com/microsoft/go-mssqldb
Zmiany importów Zamień stary zaimportowany sterownik na _ "github.com/microsoft/go-mssqldb".
Aktualizowanie parametrów połączenia Zmiana na format URL SQL Server: sqlserver://user:pass@host?database=db.
Zastąp symbole zastępcze parametrów Zmień $1/$2 lub ? z @name .sql.Named
Aktualizacja składni SQL Zmień LIMIT/OFFSET, RETURNING, NOW(), SERIAL, i inne specyficzne dla bazy danych SQL.
Zastąp operacje masowe Zmiana COPY lub LOAD DATA na mssql.CopyIn.
Schemat aktualizacji DDL Zmień SERIAL/AUTO_INCREMENT na IDENTITY, TEXT na NVARCHAR, BOOLEAN na .BIT
Testuj wszystkie zapytania Uruchom swój zestaw testowy na instancji SQL Server, aby wychwycić różnice w składni.
Konfigurowanie szyfrowania Dodaj encrypt=true (lub skorzystaj z automatycznego wykrywania platformy Azure) w środowisku produkcyjnym.
Konfigurowanie uwierzytelniania Skonfiguruj Microsoft Entra ID dla platformy Azure lub uwierzytelnianie SQL Server dla środowisk lokalnych.