Bermigrasi ke go-mssqldb dari driver lain

Panduan ini membantu pengembang Go bermigrasi dari PostgreSQL, MySQL, dan driver database lainnya ke go-mssqldb untuk SQL Server. Ini mencakup perbedaan sintaks SQL, perubahan khusus driver, dan pola yang setara untuk operasi umum.

Note

Contoh dalam artikel ini menggunakan basis data sampel AdventureWorks2025.

Mengapa bermigrasi ke SQL Server dengan go-mssqldb

Feature SQL Server dengan go-mssqldb
Keamanan perusahaan Selalu Dienkripsi, keamanan tingkat baris, penyamaran data dinamis, enkripsi data transparan (TDE).
Authentication Microsoft Entra ID (sebelumnya Azure AD), identitas terkelola, Windows authentication, Kerberos.
Integrasi Azure Dukungan Azure SQL Database asli dengan enkripsi otomatis, koneksi tanpa kata sandi, dan penanganan failover.
Performance Indeks penyimpan kolom, OLTP dalam memori, penyimpanan kueri untuk koreksi paket otomatis.
Format data Dukungan JSON dan XML bawaan dengan pengindeksan dan kueri sisi server.
Tooling SQL Server Management Studio (SSMS), Azure Data Studio, ekstensi SQL untuk Visual Studio Code.

Daftar periksa pertimbangan migrasi

Tinjau item ini sebelum Anda mulai memindahkan kueri baris demi baris:

Consideration Apa yang harus diubah
Sintaks placeholder berbeda dari banyak driver Go. Ganti ?, $1, dan placeholder serupa lainnya dengan @name atau @p1, lalu teruskan argumen sql.Named() jika perlu.
LastInsertId() tidak didukung. Gunakan OUTPUT INSERTED.<column> atau SELECT SCOPE_IDENTITY() sebagai gantinya.
Nilai Go string dipetakan ke tipe Unicode secara bawaan. Asumsikan semantik nvarchar, kecuali jika Anda memilih tipe khusus driver seperti mssql.VarChar untuk data non-Unicode.
Tabel sementara terbatas pada koneksi fisik. Pastikan logika pembuatan dan penggunaan tabel sementara tetap berada pada koneksi yang sama atau dalam transaksi yang sama jika pernyataan berikutnya bergantung pada tabel tersebut.
Autentikasi Microsoft Entra menggunakan pendaftaran driver yang berbeda. Imporgithub.com/microsoft/go-mssqldb/azuread, gunakansql.Open("azuresql", ...), dan atur opsi TLS Azure SQL secara eksplisit dengan encrypt=true&TrustServerCertificate=false.

Untuk panduan yang lebih mendalam tentang area ini, lihat Kueri dan pernyataan, Batasan, Pemetaan jenis data, autentikasi Microsoft Entra ID, dan Pemecahan Masalah.

Bermigrasi dari lib/pq (PostgreSQL)

Mengubah nama impor dan driver

Ganti lib/pq nama impor dan driver dengan 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)

Mengubah format string koneksi

Mengonversi format nilai kunci PostgreSQL ke 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"

Mengubah placeholder parameter

PostgreSQL menggunakan placeholder posisional $1, $2. SQL Server menggunakan parameter bernama dengan @:

// 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))

Perubahan sintaks SQL

Pengoperasian PostgreSQL SQL Server
Pertambahan otomatis SERIAL atau GENERATED ALWAYS AS IDENTITY IDENTITY(1,1)
Mendapatkan ID yang dimasukkan RETURNING id OUTPUT INSERTED.id atau SELECT SCOPE_IDENTITY()
Jenis Boolean BOOLEAN BIT
Penggabungan string \|\| + atau CONCAT()
Tanda waktu saat ini NOW() atau CURRENT_TIMESTAMP GETUTCDATE() atau SYSDATETIMEOFFSET()
Batasi jumlah baris LIMIT 10 OFFSET 20 OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
Jenis string TEXT atau VARCHAR NVARCHAR(MAX) atau NVARCHAR(n)
Ekstraksi JSON column->>'key' JSON_VALUE(column, '$.key')
Upsert INSERT ... ON CONFLICT DO UPDATE MERGE pernyataan
Jenis Array INTEGER[] Tidak ada array bawaan. Gunakan parameter dengan nilai tabel.
Peka huruf besar/kecil Peka huruf besar/kecil secara default Tidak membedakan huruf besar/kecil secara bawaan (bergantung pada kolasi).

Ambil ID yang dimasukkan

Ganti klausa PostgreSQL RETURNING dengan klausa SQL ServerOUTPUT:

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

Ganti LIMIT/OFFSET sintaks dengan OFFSET/FETCH NEXT sintaks.

// 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"

Bermigrasi dari pgx (PostgreSQL)

pgx Driver menggunakan kumpulan koneksi dan API sendiri yang berbeda dari database/sql. Untuk bermigrasi, beralih ke antarmuka standar database/sql .

Ubah dari kumpulan pgx ke database/sql

Ganti pgxpool API dengan antarmuka standar database/sql .

// 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))

Ganti fitur khusus pgx

Fitur PGX padanan go-mssqldb
pgx.CollectRows Manual rows.Next() dan rows.Scan() loop.
pgx.RowToStructByName Secara manual rows.Scan ke field struct.
Kueri batch (pgx.Batch) Beberapa ExecContext panggilan atau prosedur tersimpan.
COPY FROM untuk sisipan massal mssql.CopyIn untuk sisipan massal.
pgx.ConnConfig msdsn.Config atau string koneksi berbasis URL.
pgxpool.Pool sql.DB dengan SetMaxOpenConns dan SetMaxIdleConns.

Bermigrasi dari go-sql-driver/mysql (MySQL)

Tukar posisi impor MySQL dan nama driver

Ganti impor MySQL dan nama driver dengan 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)

Ubah format MySQL DSN

Konversi format MySQL DSN ke 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"

Ganti karakter pengganti tanda tanya

MySQL menggunakan ? placeholder posisional.

// 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))

Bandingkan sintaks MySQL dan SQL Server

Pengoperasian MySQL SQL Server
Pertambahan otomatis AUTO_INCREMENT IDENTITY(1,1)
Mendapatkan ID yang dimasukkan LAST_INSERT_ID() SCOPE_IDENTITY() atau OUTPUT INSERTED.id
Batasi jumlah baris LIMIT 10 OFFSET 20 OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
Tanda waktu saat ini NOW() GETUTCDATE()
Jika null IFNULL(expr, default) ISNULL(expr, default) atau COALESCE(expr, default)
Panjang string LENGTH(str) LEN(str)
Substring SUBSTRING(str, start, len) SUBSTRING(str, start, len) (sama)
Format tanggal DATE_FORMAT(d, '%Y-%m-%d') FORMAT(d, 'yyyy-MM-dd') atau CONVERT(VARCHAR, d, 23)
Upsert INSERT ... ON DUPLICATE KEY UPDATE MERGE pernyataan
Penggunaan backtick sebagai tanda kutip `column` [column]

Ganti sintaks khusus MySQL

Sintaks MySQL Setara dengan SQL Server
AUTO_INCREMENT IDENTITY(1,1)
LIMIT n OFFSET m OFFSET m ROWS FETCH NEXT n ROWS ONLY(membutuhkan)ORDER BY

AUTO_INCREMENT ke 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 ke 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;

Pola migrasi umum

Mendapatkan identitas terakhir yang disisipkan

Gunakan OUTPUT klausa atau SCOPE_IDENTITY() untuk mengambil nilai identitas baris yang disisipkan:

// 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)

Tip

Lebih suka OUTPUT klausa daripada SCOPE_IDENTITY(). Klausa OUTPUT berfungsi dengan penyisipan batch dan tidak bergantung pada urutan pernyataan.

Upsert (sisipkan atau perbarui)

ON CONFLICT milik PostgreSQL dan ON DUPLICATE KEY UPDATE milik MySQL dipetakan ke MERGE milik 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))

Penyisipan massal

Ganti PostgreSQL COPY atau MySQL LOAD DATA dengan 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()

Menangani nilai NULL

Semua driver database Go menangani nilai NULL dengan cara yang sama karena mereka menggunakan jenisnya 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

Semua driver database Go menggunakan API transaksi yang sama database/sql .

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()

Daftar periksa migrasi

Step Action
Pasang driver go get github.com/microsoft/go-mssqldb
Ubah impor Ganti impor driver lama dengan _ "github.com/microsoft/go-mssqldb".
Memperbarui string koneksi Ubah ke format URL SQL Server: sqlserver://user:pass@host?database=db.
Mengganti placeholder parameter Ubah $1/$2 atau ? menjadi @name dengan .sql.Named
Perbarui sintaks SQL Ubah LIMIT/OFFSET, RETURNING, , NOW(), SERIALdan SQL khusus database lainnya.
Mengganti operasi massal Ubah COPY atau LOAD DATA menjadi mssql.CopyIn.
Perbarui skema DDL Ubah SERIAL/AUTO_INCREMENT menjadi IDENTITY, TEXT menjadi , NVARCHAR menjadi .BOOLEANBIT
Uji semua kueri Jalankan rangkaian pengujian Anda terhadap instans SQL Server untuk menangkap perbedaan sintaks.
Konfigurasikan enkripsi Tambahkan encrypt=true (atau andalkan deteksi otomatis Azure) untuk produksi.
Mengonfigurasikan autentikasi Konfigurasikan Microsoft Entra ID untuk Azure, atau autentikasi SQL Server untuk lokal.