Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
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. |