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.
sqlx to lekka biblioteka, która rozszerza Go database/sql o skanowanie struktur, wiązanie parametrów o nazwy oraz pomocników zapytań. Działa z dowolnym sterownikiem database/sql, w tym go-mssqldb.
W przeciwieństwie do ORM, sqlx nie generuje SQL ani nie zarządza schematami. Ty piszesz zapytania, a sqlx obsługuje mapowanie między zestawami wyników a strukturami Go. Ta równowaga sprawia, że jest to dobry wybór, gdy chcesz pisać mniej powtarzalnego kodu niż przy użyciu samego database/sql, ale bez abstrakcji pełnego ORM.
Przykłady w tym artykule porównane są z przykładową bazą danych AdventureWorks2025 .
Instaluj sqlx
Stwórz lub otwórz moduł Go, a następnie dodaj sqlx i :go-mssqldb
mkdir go-sqlx-sqlserver
cd go-sqlx-sqlserver
go mod init example.com/go-sqlx-sqlserver
go get github.com/jmoiron/sqlx
go get github.com/microsoft/go-mssqldb
Nawiązywanie połączenia z programem SQL Server
Otwórz połączenie za pomocą sqlx.Open o nazwie sterownika sqlserver:
package main
import (
"fmt"
"log"
"github.com/jmoiron/sqlx"
_ "github.com/microsoft/go-mssqldb"
)
func main() {
// Replace <server>, <user>, and <password> with your own values.
// In production, load credentials from environment variables or a secret store.
dsn := "sqlserver://<user>:<password>@<server>.database.windows.net:1433?database=AdventureWorks2025&encrypt=true&TrustServerCertificate=false"
db, err := sqlx.Open("sqlserver", dsn)
if err != nil {
log.Fatal(err)
}
defer db.Close()
if err := db.Ping(); err != nil {
log.Fatal(err)
}
fmt.Println("Connected to SQL Server with sqlx")
}
sqlx.Open zwraca obiekt *sqlx.DB, który opakowuje standardowy *sql.DB. Wszystkie database/sql metody nadal działają, plus rozszerzenia sqlx opisane w tym artykule.
Skanowanie struktury za pomocą Select i Get
Główną zaletą sqlx w porównaniu do raw database/sql jest automatyczne skanowanie struktur. Przypisz kolumny do pól struktury za pomocą znaczników db:
type Product struct {
ProductID int32 `db:"ProductID"`
Name string `db:"Name"`
ListPrice float64 `db:"ListPrice"`
}
Wybierz wiele wierszy
Select skanuje wszystkie wiersze wynikowe do wycinka struktur:
var products []Product
err := db.Select(&products,
"SELECT TOP 5 ProductID, Name, ListPrice FROM Production.Product WHERE ListPrice > @p1 ORDER BY ListPrice DESC",
sql.Named("p1", 1000))
if err != nil {
log.Fatal(err)
}
for _, p := range products {
fmt.Printf("%-35s $%.2f\n", p.Name, p.ListPrice)
}
Select wykonuje zapytanie, skanuje każdy wiersz w strukturę i zamyka iterator wiersza. Zastępuje Query / for rows.Next() / rows.Scan() wzór.
Pobierz pojedynczy wiersz
Get skanuje pierwszy wiersz do pojedynczej struktury:
var product Product
err := db.Get(&product,
"SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ProductID = @p1",
sql.Named("p1", 680))
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s: $%.2f\n", product.Name, product.ListPrice)
Get zwraca, sql.ErrNoRows jeśli zapytanie nie zwraca żadnych wierszy. Jeśli wiele wierszy się zgadza, skanowany jest tylko pierwszy.
Nazwane parametry
SQLX obsługuje :name parametry nazwane stylem, wykorzystując mapy lub struktury jako źródło parametrów. Jednak go-mssqldb natywnie używa parametrów @name, więc w przypadku SQL Server użyj sql.Named ze standardowymi symbolami zastępczymi @p1, jak pokazano w poprzednich przykładach.
Jeśli wolisz składnię :name biblioteki sqlx, użyj sqlx.Named, aby ponownie powiązać:
query, args, err := sqlx.Named(
"SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ProductID = :id",
map[string]interface{}{"id": 680})
if err != nil {
log.Fatal(err)
}
// Rebind to positional placeholders for go-mssqldb
query = db.Rebind(query)
var product Product
err = db.Get(&product, query, args...)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s: $%.2f\n", product.Name, product.ListPrice)
Uwaga / Notatka
sqlx.Named konwertuje symbole zastępcze :name na parametry pozycyjne ?.
Rebind następnie konwertuje do ? formatu docelowego sterownika. Stosuj to dwustopniowe podejście, gdy chcesz zapewnić przenośną obsługę nazwanych parametrów w różnych sterownikach.
Rozwinięcie klauzuli IN
Budowanie WHERE column IN (...) klauzul o zmiennej liczbie wartości jest żmudne przy czystym SQL. Użyj sqlx.In, aby rozwinąć wycinek do postaci pojedynczych symboli zastępczych:
ids := []int32{680, 706, 707}
query, args, err := sqlx.In(
"SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ProductID IN (?)", ids)
if err != nil {
log.Fatal(err)
}
query = db.Rebind(query)
var products []Product
err = db.Select(&products, query, args...)
if err != nil {
log.Fatal(err)
}
for _, p := range products {
fmt.Printf("%d: %s ($%.2f)\n", p.ProductID, p.Name, p.ListPrice)
}
sqlx.In Rozszerza pojedynczy ? fragment do ?, ?, ? listy ARGS i spłaszcza wycinek.
Rebind następnie konwertuje do formatu symbolu zastępczego sterownika.
Wykonywanie zapisów
Zastosowanie Exec dla INSERT, UPDATE, i DELETE zdań. Te przykłady dotyczą Production.ScrapReason, więc nie modyfikują kluczowych tabel.
Uwaga
sqlx oferuje również MustExec, które zamiast zwracać błąd powoduje panikę. Unikaj używania MustExec w usługach produkcyjnych, ponieważ panic, po której nie następuje odzyskanie, powoduje zakończenie procesu. W przykładach w tej sekcji użyto Exec z jawnym sprawdzaniem błędów.
Wstaw wiersz
Użyj Exec z instrukcją INSERT i nazwanymi parametrami:
result, err := db.Exec(
"INSERT INTO Production.ScrapReason (Name, ModifiedDate) VALUES (@p1, @p2)",
sql.Named("p1", "sqlx test scrap"), sql.Named("p2", time.Now()))
if err != nil {
log.Fatal(err)
}
affected, _ := result.RowsAffected()
fmt.Printf("Inserted %d row(s)\n", affected)
// Clean up
db.Exec("DELETE FROM Production.ScrapReason WHERE Name = @p1",
sql.Named("p1", "sqlx test scrap"))
Transakcja z sqlx
Opakuj operacje w transakcję, używając Beginx:
tx, err := db.Beginx()
if err != nil {
log.Fatal(err)
}
defer tx.Rollback() // no-op after Commit, but essential if an error occurs
if _, err := tx.Exec(
"INSERT INTO Production.ScrapReason (Name, ModifiedDate) VALUES (@p1, @p2)",
sql.Named("p1", "sqlx tx scrap 1"), sql.Named("p2", time.Now())); err != nil {
log.Fatal(err)
}
if _, err := tx.Exec(
"INSERT INTO Production.ScrapReason (Name, ModifiedDate) VALUES (@p1, @p2)",
sql.Named("p1", "sqlx tx scrap 2"), sql.Named("p2", time.Now())); err != nil {
log.Fatal(err)
}
if err := tx.Commit(); err != nil {
log.Fatal(err)
}
fmt.Println("Transaction committed")
// Clean up
db.Exec("DELETE FROM Production.ScrapReason WHERE Name IN (@p1, @p2)",
sql.Named("p1", "sqlx tx scrap 1"), sql.Named("p2", "sqlx tx scrap 2"))
Wywołanie defer tx.Rollback() zapewnia wycofanie transakcji w przypadku niepowodzenia dowolnej operacji. Po udanym Commit, Rollback jest bezpieczny no-op. Obiekt tx udostępnia te same funkcje pomocnicze sqlx (Select, Get, Exec) ograniczone do transakcji.
Skanowanie struktur ze złączeniami
sqlx może skanować kolumny z połączonych zapytań w strukturę płaską lub osadzoną.
type ProductWithCategory struct {
ProductID int32 `db:"ProductID"`
ProductName string `db:"ProductName"`
CategoryName string `db:"CategoryName"`
ListPrice float64 `db:"ListPrice"`
}
var results []ProductWithCategory
err := db.Select(&results, `
SELECT TOP 5
p.ProductID,
p.Name AS ProductName,
pc.Name AS CategoryName,
p.ListPrice
FROM Production.Product p
JOIN Production.ProductSubcategory ps ON p.ProductSubcategoryID = ps.ProductSubcategoryID
JOIN Production.ProductCategory pc ON ps.ProductCategoryID = pc.ProductCategoryID
WHERE p.ListPrice > @p1
ORDER BY p.ListPrice DESC`,
sql.Named("p1", 1000))
if err != nil {
log.Fatal(err)
}
for _, r := range results {
fmt.Printf("%-35s %-15s $%.2f\n", r.ProductName, r.CategoryName, r.ListPrice)
}
Kiedy wybrać sqlx, GORM czy database/sql
| Wybierz... | Kiedy najlepiej pasuje |
|---|---|
database/sql |
Nie chcesz żadnych zależności poza sterownikiem albo musisz mieć pełną kontrolę nad każdym zapytaniem. |
| sqlx | Potrzebujesz skanowania struktur i narzędzi pomocniczych do zapytań bez warstwy abstrakcji ORM. |
| GORM | Chcesz zarządzania schematami, skojarzeń, hooków i pełnego zestawu funkcji ORM. |