Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
GORM ist ein beliebtes Go-ORM, das SQL Server über den Dialekt gorm.io/driver/sqlserver unterstützt, der intern go-mssqldb verwendet. GORM übernimmt Schema-Unterschiede, Abfragegenerierung und Typzuordnung, sodass du mit Go-Structs arbeiten kannst, anstatt rohes SQL zu schreiben.
Dieser Artikel behandelt GORM-Muster, die spezifisch für SQL Server sind. Für die allgemeine Verwendung von GORM siehe die GORM-Dokumentation.
Beispiele in diesem Artikel laufen gegen die AdventureWorks2025-Beispieldatenbank .
Installiere GORM und den SQL Server-Dialekt
Erstelle oder öffne ein Go-Modul, dann füge GORM und den SQL Server-Dialekt hinzu:
mkdir go-gorm-sqlserver
cd go-gorm-sqlserver
go mod init example.com/go-gorm-sqlserver
go get gorm.io/gorm
go get gorm.io/driver/sqlserver
Verbindung mit SQL Server herstellen
Eröffne eine GORM-Sitzung, indem du ein sqlserver:// DSN an den Dialekt übergibst:
package main
import (
"fmt"
"log"
"gorm.io/driver/sqlserver"
"gorm.io/gorm"
)
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 := gorm.Open(sqlserver.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
sqlDB, err := db.DB()
if err != nil {
log.Fatal(err)
}
defer sqlDB.Close()
fmt.Println("Connected to SQL Server with GORM")
}
Der Dialekt verwendet intern den go-mssqldb-Treiber, sodass alle Verbindungsoptionen aus Verbindungszeichenfolgen und Verbindungsoptionen für den DSN gelten.
Modelle vorhandenen Tabellen zuordnen
Die Standardnamenskonvention von GORM verwendet kleine Plural-Tabellennamen (zum Beispiel products), was nicht mit den SQL Server-Konventionen übereinstimmt. Verwenden Sie die Methode TableName() , um ein Modell an eine bestehende, schema-qualifizierte Tabelle zu binden:
type Product struct {
ProductID int32 `gorm:"column:ProductID;primaryKey"`
Name string `gorm:"column:Name"`
ProductLine *string `gorm:"column:ProductLine"`
ListPrice float64 `gorm:"column:ListPrice"`
}
func (Product) TableName() string {
return "Production.Product"
}
Tip
Definieren Sie TableName() immer, wenn Sie mit bestehenden SQL Server-Datenbanken arbeiten. Die Verwendung von GORMs automatischer Pluralisierung führt bei Tabellen, die den SQL-Server-Namenskonventionen folgen, zu Fehlern wie „ungültiger Objektname“.
Abfragedaten
Nachdem Sie ein Modell definiert haben, verwenden Sie die Abfragemethoden von GORM, um die Daten auszulesen:
Suchen Sie Zeilen mit einer WHERE-Klausel
Filtern, sortieren und begrenzen Sie die Ergebnisse mit Where, Order, und Limit:
var products []Product
result := db.Where("ListPrice > ?", 1000).
Order("ListPrice DESC").
Limit(5).
Find(&products)
if result.Error != nil {
log.Fatal(result.Error)
}
for _, p := range products {
fmt.Printf("%-35s $%.2f\n", p.Name, p.ListPrice)
}
Eine einzelne Zeile abrufen
Verwenden Sie First mit einer Bedingung, um einen Datensatz zu laden:
var product Product
if err := db.First(&product, "ProductID = ?", 680).Error; err != nil {
log.Fatal(err)
}
fmt.Printf("%s: $%.2f\n", product.Name, product.ListPrice)
Zeilenanzahl
Verwenden Sie Count für einen Modellbereich, um die Zeilenanzahl abzurufen:
var count int64
db.Model(&Product{}).Where("ListPrice > ?", 0).Count(&count)
fmt.Printf("Products with a list price: %d\n", count)
Zeilen einfügen, aktualisieren und löschen
Schreiboperationen verwenden dieselben Modellstrukturen. Die Beispiele in diesem Abschnitt verwenden Production.ScrapReason, damit sie keine kritischen Tabellen verändern.
type ScrapReason struct {
ScrapReasonID int16 `gorm:"column:ScrapReasonID;primaryKey;autoIncrement"`
Name string `gorm:"column:Name"`
ModifiedDate time.Time `gorm:"column:ModifiedDate"`
}
func (ScrapReason) TableName() string {
return "Production.ScrapReason"
}
Fügen Sie eine Reihe ein
Übergib eine gefüllte Struktur an Create, um eine Zeile einzufügen und den automatisch generierten Primärschlüssel zu setzen:
reason := ScrapReason{Name: "GORM test scrap", ModifiedDate: time.Now()}
if err := db.Create(&reason).Error; err != nil {
log.Fatal(err)
}
fmt.Printf("Inserted ScrapReasonID: %d\n", reason.ScrapReasonID)
// Clean up
db.Delete(&reason)
Zeile aktualisieren
Verwenden Sie Model mit Update, um einen Spaltenwert zu ändern:
reason := ScrapReason{Name: "GORM update test", ModifiedDate: time.Now()}
db.Create(&reason)
db.Model(&reason).Update("Name", "GORM updated scrap")
var updated ScrapReason
db.First(&updated, reason.ScrapReasonID)
fmt.Printf("Updated name: %s\n", updated.Name)
// Clean up
db.Delete(&reason)
Zeile löschen
Übergebe eine Struktur mit einem befüllten Primärschlüssel an Delete:
reason := ScrapReason{Name: "GORM delete test", ModifiedDate: time.Now()}
db.Create(&reason)
id := reason.ScrapReasonID
db.Delete(&reason)
var count int64
db.Model(&ScrapReason{}).Where("ScrapReasonID = ?", id).Count(&count)
fmt.Printf("Rows remaining with that ID: %d\n", count)
Batch-Insert und das 2.100-Parameter-Limit
SQL Server begrenzt sp_executesql auf 2.100 Parameter pro Anweisung. Der Batch-Insert von GORM erzeugt eine Mehrzeilenklausel VALUES , bei der jede Spalte einen Parameter verbraucht, sodass eine Tabelle mit 10 Spalten bei etwa 210 Zeilen pro Charge an die Grenze trifft.
Legen Sie CreateBatchSize für die Sitzung fest, damit sie innerhalb des Limits bleibt:
reasons := make([]ScrapReason, 50)
for i := range reasons {
reasons[i] = ScrapReason{
Name: fmt.Sprintf("Batch scrap %d", i+1),
ModifiedDate: time.Now(),
}
}
// 2 inserted columns per row (Name, ModifiedDate; the autoIncrement ID is excluded),
// so batches of 500 are well within the 2,100-parameter limit.
result := db.CreateInBatches(&reasons, 500)
if result.Error != nil {
log.Fatal(result.Error)
}
fmt.Printf("Inserted %d rows in batches\n", result.RowsAffected)
// Clean up
for _, r := range reasons {
db.Delete(&r)
}
Bei Tabellen mit vielen Spalten sollte die Batch-Größe proportional reduziert werden. Eine sichere Formel: batch size = floor(2100 / number of inserted columns).
Transaktionen
Mehrere Operationen in einer GORM-Transaktion umwickeln:
err := db.Transaction(func(tx *gorm.DB) error {
r1 := ScrapReason{Name: "TX scrap 1", ModifiedDate: time.Now()}
if err := tx.Create(&r1).Error; err != nil {
return err
}
r2 := ScrapReason{Name: "TX scrap 2", ModifiedDate: time.Now()}
if err := tx.Create(&r2).Error; err != nil {
return err
}
// Both inserts commit together.
fmt.Printf("Inserted IDs: %d, %d\n", r1.ScrapReasonID, r2.ScrapReasonID)
// Clean up inside the same transaction.
tx.Delete(&r1)
tx.Delete(&r2)
return nil
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Transaction committed")
Wenn der Rückruf einen Fehler zurückgibt, rollt GORM automatisch zurück.
Ausweichlösung für rohes SQL
Wenn der Abfrage-Builder von GORM nicht die benötigte SQL Server-Syntax generiert, schalte auf rohes SQL zurück, während du weiterhin die GORM-Sitzung verwendest:
var results []struct {
Name string
ListPrice float64
}
result := db.Raw("SELECT TOP 5 Name, ListPrice FROM Production.Product WHERE ListPrice > @price ORDER BY ListPrice DESC",
sql.Named("price", 1000)).Scan(&results)
if result.Error != nil {
log.Fatal(result.Error)
}
for _, r := range results {
fmt.Printf("%-35s $%.2f\n", r.Name, r.ListPrice)
}
Raw-Abfragen verwenden denselben von GORM verwalteten Verbindungspool, sodass die Pooleinstellungen von db.DB() weiterhin gelten.
Konfigurieren Sie den Verbindungspool
Greifen Sie auf die zugrunde liegende *sql.DB Parameter zu, um Pool-Parameter festzulegen:
sqlDB, err := db.DB()
if err != nil {
log.Fatal(err)
}
sqlDB.SetMaxOpenConns(25)
sqlDB.SetMaxIdleConns(10)
sqlDB.SetConnMaxLifetime(5 * time.Minute)
Für Hinweise zur Poolgröße siehe Connection Pooling.
Überlegungen zu AutoMigrate
AutoMigrate erstellt oder verändert Tabellen, um sie an Ihre Modelldefinitionen anzupassen. Es funktioniert mit SQL Server, aber seien Sie sich dieser Verhaltensweisen bewusst:
-
AutoMigrateerstellt Tabellen im Standardschema (dbo), es sei denn, du überschreibstTableName()mit einem Schemapräfix. - Es fügt fehlende Spalten hinzu und erstellt Indizes, entfernt aber keine Spalten und ändert keine bestehenden Spaltentypen.
- SQL Server hat eine Begrenzung von 128 Zeichen für Indexnamen. Die von GORM generierten Indexnamen können diese Grenze bei Tabellen mit langen Namen oder zusammengesetzten Indizes überschreiten. Verwende explizite Tags,
gorm:"index:idx_short_name"wenn du dieses Limit erreichst.
Für Produktionsdatenbanken mit verwalteten Schemata bevorzugen Sie Migrationstools gegenüber AutoMigrate.