Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A Production Go alkalmazásoknak strukturált hibakezelésre van szükségük, hogy megkülönböztessék az átmeneti hibákat, amelyeket újra meg lehet próbálni, és az emberi beavatkozást igénylő tartós hibáktól. Ez a cikk a hibaosztályozást, az újrapróbálási mintákat és a vezetői ellenálló képesség stratégiáit go-mssqldb tárgyalja.
SQL Server hibaszerkezete
Amikor az SQL Server hibát ad vissza, az go-mssqldb illesztőprogram egy mssql.Error struktúrába csomagolja azt. Használjon típusállítást a strukturált hibamezők eléréséhez:
import (
"database/sql"
"errors"
"fmt"
mssql "github.com/microsoft/go-mssqldb"
)
func handleError(err error) {
var mssqlErr mssql.Error
if errors.As(err, &mssqlErr) {
fmt.Printf("Number: %d\n", mssqlErr.Number)
fmt.Printf("State: %d\n", mssqlErr.State)
fmt.Printf("Class: %d\n", mssqlErr.Class)
fmt.Printf("Message: %s\n", mssqlErr.Message)
fmt.Printf("Server: %s\n", mssqlErr.ServerName)
fmt.Printf("Proc: %s\n", mssqlErr.ProcName)
fmt.Printf("Line: %d\n", mssqlErr.LineNo)
}
}
Hibamezők
| Field | Típus | Description |
|---|---|---|
Number |
int32 |
SQL Server hibaszám. Térképek a sys.messages. |
State |
uint8 |
Hibaállapot. További kontextust ad ugyanahhoz a hibaszámhoz. |
Class |
uint8 |
Súlyossági szint (0-25). A 11–16 közötti súlyossági szintek a felhasználó által javíthatók. 17+ súlyosság erőforrás- vagy rendszerproblémákat jelez. |
Message |
string |
Ember által olvasható hibaüzenet a szerverről. |
ServerName |
string |
Az SQL Server példány neve, amely a hibát okozta. |
ProcName |
string |
A hiba bekövetkezett helyén tárolt eljárás vagy függvénynév. Üres ad hoc lekérdezésekhez. |
LineNo |
int32 |
A sor száma a Transact-SQL (T-SQL) kötetben vagy tárolt eljárásban. |
Súlyossági szintek
| Súlyossági tartomány | Meaning | Action |
|---|---|---|
| 0-10 | Tájékoztató üzenetek | Nincs hiba. Naplózd, ha szükséges. |
| 11-16 | Felhasználó által javítható hibák | Javítsd meg a lekérdezést, paramétereket vagy jogosultságokat. |
| 17-19 | Erőforráshibák | Próbálkozzon újra. Lehet, hogy a szerver terhelés alatt vagy erőforrásai fogynak. |
| 20-25 | Végzetes hibák | A kapcsolat megszakadt. Csatlakozzon újra, és próbálja újra. |
Osztályozza a hibákat átmenetiként vagy állandóként
Átmeneti hibák ideiglenes állapotok, amelyek önmaguktól oldódnak, mint például hálózati zavarok, kapcsolati korlátozások vagy rövid erőforrás-vita. A tartós hibák kód- vagy konfigurációs változtatásokat igényelnek.
Gyakori átmeneti hibaszámok
Használja az alábbi megosztott katalógust az átmeneti kapcsolat-létrehozás és kérés-út szállítási hibák kanonikus listájáként:
A következő hibák átmenetiek, amikor a kapcsolat létrehozásakor vagy a kiszolgálónak küldött kérések során fordulnak elő. Próbálkozzon újra rövid, korlátozott várakozási idő után. A néhány újrapróbálkozást követő hibák általában olyan konfigurációs problémát jeleznek (hibás kiszolgáló, hiányzó engedélyek, kimerült kvóta), amely az újrapróbálkozást nem oldja meg.
| Error | Message | Hibaelhárítás |
|---|---|---|
64 |
A connection was successfully established with the server, but then an error occurred during the login process. (provider: TCP Provider, error: 0 - The specified network name is no longer available.) |
A TCP-kapcsolat kézfogás közben megszakad. Ez nem hitelesítési hiba. Ha továbbra is fennáll, ellenőrizze az ügyféloldali hálózati instabilitást, vagy egy olyan köztes eszközt, amely megszakítja a félig létrehozott kapcsolatokat. |
233 |
The client was unable to establish a connection because of an error during connection initialization process before login. |
Bejelentkezés előtti átvitel vagy TLS-hiba. A kiszolgáló általában akkor adja vissza, ha nem tudja elfogadni a kapcsolatot (erőforrás-kimerültség, elért maximális kapcsolatok vagy nem támogatott ügyfél). Ez nem hitelesítési hiba. Ellenőrizze a kiszolgáló állapotát, majd ellenőrizze az ügyfél bejelentkezési időtúllépését, a TLS-beállításokat és az ügyfél/kiszolgáló TLS-verziókompatibilitását. |
4060 |
Cannot open database "%.*ls" requested by the login. The login failed. |
A bejelentkezés hitelesít, de nem tudja megnyitni a kért adatbázist. Az átmeneti okok közé tartozik, ha az adatbázis átmeneti állapotban van (feladatátvétel, visszaállítás, skálázás miatt), vagy automatikusan szüneteltetve van. Az állandó okok (az adatbázis nem létezik, a bejelentkezés nem rendelkezik hozzáféréssel) nem lesznek javítva újrapróbálkozással; ellenőrizze az adatbázis nevét, a bejelentkezési leképezést és az adatbázis állapotát. |
4221 |
Login to read-secondary failed due to long wait on 'HADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING'. |
A replika nem érhető el bejelentkezéshez, mert a sorverziók hiányoznak a replika újrafeldolgozásakor repülés közben végrehajtott tranzakciókhoz. A probléma megoldásához vonja vissza vagy véglegesítse az aktív tranzakciókat az elsődleges kiszolgálón. Csökkentse ezt azzal, hogy kerüli a hosszú írási tranzakciókat az elsődleges csomóponton. |
10053 |
A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An established connection was aborted by the software in your host machine.) |
A helyi oldal megszakítja a kapcsolatot. Ellenőrizze az ügyféloldali hálózat állapotát, valamint a helyi tűzfal vagy VPN-ügyfél állapotát. |
10054 |
A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.) |
A távoli oldal TCP-alaphelyzetbe állítást küld. Gyakori okok: a partnerfolyamat összeomlott, egy tűzfal resetet küldött, vagy az Azure SQL-átjáró lezárt egy inaktív kapcsolatot. Tétlenség miatti kapcsolatbontási minták esetén engedélyezze a TCP keepalive funkciót az ügyféloldalon, vagy csökkentse a kapcsolatpool tétlenségi időkorlátját. |
10928 |
Resource ID: %d. The %s limit for the database is %d and has been reached. See 'http://go.microsoft.com/fwlink/?LinkId=267637' for assistance. |
Az adatbázis túllépi a Azure SQL erőforrás-szabályozási korlátot. Az 1. erőforrás-azonosító a feldolgozói korlátot jelzi; A 2. erőforrás-azonosító a munkamenetkorlátot jelzi. Azonosítsa az üzenet korláttípusát, majd csökkentse az egyidejűséget, skálázza fel az adatbázist, vagy lerövidítse az erőforrást tartalmazó hosszú ideig futó műveleteket. |
10929 |
Resource ID: %d. The %s minimum guarantee is %d, maximum limit is %d, and the current usage for the database is %d. However, the server is currently too busy to support requests greater than %d for this database. |
Az adatbázis meghaladja a számára garantált minimumot, és a mögöttes kiszolgáló korlátozza a teljesítményét. Az újrapróbálkozás általában akkor sikeres, ha a szomszéd terhelés csökken. A tartós előfordulások azt jelzik, hogy magasabb szolgáltatási szintre vagy kevésbé zajos környezetre van szüksége. |
40020, 40143, 40166, 40540 |
Error code %d A 40197-es hibahelyen jelentve a feladatátvétel során. |
A 40197-es feladatátvételi üzenetbe beágyazott alkódok, amelyek egyes útvonalakon legfelső szintű hibaszámként jelennek meg. Kezelje őket ugyanúgy, mint a 40197-et. |
40197 |
The service has encountered an error processing your request. Please try again. Error code %d. |
Szoftverfrissítés, hardverhiba vagy más feladatátvételi esemény az Azure SQL-ben. Az újracsatlakozás egy működőképes replikához kapcsol. A beágyazott hibakód azonosítja a feladatátvétel típusát. Ha a hiba továbbra is fennáll, rögzítse a munkamenet-nyomkövetés azonosítóját, és forduljon az ügyfélszolgálathoz. |
40501 |
The service is currently busy. Retry the request after 10 seconds. Incident ID: %ls. Code: %d. |
Azure SQL motor szabályozása. Az ajánlott minimális várakozási idő 10 másodperc. A tartós korlátozás azt jelzi, hogy a munkaterhelés túllépte az adatbázis erőforrás-kiosztását; növelje a szolgáltatási szintet, vagy csökkentse a párhuzamosságot. |
40613 |
Database '%.*ls' on server '%.*ls' is not currently available. Please retry the connection later. If the problem persists, contact customer support, and provide them with the session tracing ID of '%.*ls'. |
Az adatbázis nem érhető el, általában feladatátvétel alatt vagy rövid ideig egy skálázási művelet közben. Próbálkozzon újra egy visszalépéssel; ha néhány perc elteltével is megmarad, rögzítse a munkamenet nyomkövetési azonosítóját, és nyisson meg egy támogatási esetet. |
42108 |
Can not connect to the SQL pool since it is paused. Please resume the SQL pool and try again. |
A dedikált SQL-készlet (Synapse) szüneteltetett állapotban van. Az újrapróbálás csak a készlet újraindítása után sikerül. Állítsa vissza explicit módon a készletet működő állapotba, vagy ütemezze a munkaterhelés futtatását a készlet folytatását követő időpontra. |
42109 |
The SQL pool is warming up. Please try again. |
A dedikált SQL-készlet újra működik. Próbálkozzon újra egyre hosszabb várakozási időkkel, amíg a pool online nem lesz; a bemelegítés általában néhány percet vesz igénybe. |
49918 |
Cannot process request. Not enough resources to process request. The service is currently busy. Please retry the request later. |
A kiszolgáló jelenleg nem tud elegendő erőforrást lefoglalni a kérés teljesítéséhez. Próbálkozzon újra egy visszalépéssel. Ha a hiba továbbra is fennáll, skálázza fel az adatbázist vagy a rugalmas készletet. |
49919 |
Cannot process create or update request. Too many create or update operations in progress for subscription "%ld". |
Előfizetési szintű egyidejűségi korlát a felügyeleti műveletekre. Csökkentse a párhuzamos létrehozási vagy frissítési hívások számát, vagy időben tolja el őket. |
49920 |
Cannot process request. Too many operations in progress for subscription "%ld". |
Előfizetésszintű egyidejűségi korlát a repülési műveletekre. Csökkentse a párhuzamosságot, vagy várja meg, amíg a folyamatban lévő műveletek befejeződnek. |
Az utasításszintű hibák nem szerepelnek ezen a listán, mert a kapcsolat létrejötte után jelentkeznek, és a hiba ellenére a munkamenet továbbra is használható marad. A leggyakoribb újrapróbálkozható utasításhibák az 1205 (holtpont áldozata) és az 1222 (zárolási kérelem időtúllépése). Az egyetlen sikertelen utasítás helyett próbálkozzon újra a teljes tranzakcióval.
A hibaüzenet szövege Azure SQL átmeneti kapcsolati hibákból származik. Az egyes illesztőprogramok saját beépített újrapróbálkozási listákat tartanak fenn; ez a katalógus azt írja le, hogy mely hibák alkalmasak az újrapróbálkozásra az SQL Server, az Azure SQL Database, az Azure SQL Managed Instance, a Microsoft Fabric SQL-adatbázisa és az Azure Synapse Analytics dedikált SQL-készletei esetén.
A következő isTransient függvény egy Go megvalósítási mintát mutat az újrapróbálkozás osztályozásához. Kezeld a fenti megosztott katalógust az igazság forrásának, és tartsd a kódkeresésed összhangban vele.
// isTransient returns true if the error is a transient SQL Server error
// that is likely to succeed on retry.
func isTransient(err error) bool {
var mssqlErr mssql.Error
if !errors.As(err, &mssqlErr) {
// Network errors, context deadlines, and connection resets
// are also transient.
return isNetworkError(err)
}
if isTransientSQLNumber(mssqlErr.Number) {
return true
}
// Severity 17-19 indicates resource issues that are typically transient.
return mssqlErr.Class >= 17 && mssqlErr.Class <= 19
}
// Keep this lookup synchronized with the shared transient catalog above.
var transientSQLNumbers = map[int32]struct{}{
64: {}, // Transport/connection error.
1205: {}, // Deadlock victim.
40197: {}, // Service error processing request.
40501: {}, // Service is currently busy.
40613: {}, // Database is currently unavailable.
49918: {}, // Cannot process request: not enough resources.
49919: {}, // Cannot process create/update request.
49920: {}, // Cannot process request: too many operations.
}
func isTransientSQLNumber(number int32) bool {
_, ok := transientSQLNumbers[number]
return ok
}
Ha konfigurációs és kvótahibákat tapasztalsz, javítsd meg az alapkapacitást, adatbázist vagy hálózati konfigurációt, mielőtt újra próbálnád. Ide sorolhatóak például a következők:
-
40544(adatbázis méretkvóta) -
4060(nem lehet adatbázist nyitni) -
40615(tűzfal szabály)
Hálózati hibák észlelése
A hálózati szintű hibák nem hoznak mssql.Error létre értékeket. Ellenőrizd a Go hálózati gyakori hibatípusokat:
import (
"context"
"errors"
"net"
"io"
)
func isNetworkError(err error) bool {
if err == nil {
return false
}
// Context deadline exceeded or canceled
if errors.Is(err, context.DeadlineExceeded) {
return true
}
// Connection reset or broken pipe
var netErr *net.OpError
if errors.As(err, &netErr) {
return true
}
// Unexpected EOF (server dropped the connection)
if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) {
return true
}
return false
}
Újrapróbálkozás megvalósítása exponenciális késleltetéssel
Átmeneti hibák esetén próbálkozzon újra, az egyes próbálkozások között növekvő várakozási idővel. Ez a megközelítés időt ad a szervernek a helyreállításra, és elkerüli, hogy gyors próbálkozásokkal túlterhelje azt.
import (
"context"
"database/sql"
"errors"
"fmt"
"log"
"math"
"math/rand"
"time"
mssql "github.com/microsoft/go-mssqldb"
)
// RetryConfig controls retry behavior.
type RetryConfig struct {
MaxAttempts int // Maximum number of attempts (including the first).
BaseDelay time.Duration // Initial delay before the first retry.
MaxDelay time.Duration // Upper bound on delay between retries.
}
// DefaultRetryConfig provides sensible defaults for SQL Server workloads.
var DefaultRetryConfig = RetryConfig{
MaxAttempts: 5,
BaseDelay: 100 * time.Millisecond,
MaxDelay: 10 * time.Second,
}
// RetryFunc executes fn with retries for transient errors.
func RetryFunc(ctx context.Context, cfg RetryConfig, fn func(ctx context.Context) error) error {
var lastErr error
for attempt := 0; attempt < cfg.MaxAttempts; attempt++ {
lastErr = fn(ctx)
if lastErr == nil {
return nil
}
if !isTransient(lastErr) {
return lastErr // Permanent error, don't retry.
}
if attempt == cfg.MaxAttempts-1 {
break // Last attempt, don't sleep.
}
delay := calculateDelay(attempt, cfg.BaseDelay, cfg.MaxDelay)
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(delay):
}
}
return lastErr
}
func calculateDelay(attempt int, baseDelay, maxDelay time.Duration) time.Duration {
// Exponential backoff: base * 2^attempt
delay := time.Duration(float64(baseDelay) * math.Pow(2, float64(attempt)))
if delay > maxDelay {
delay = maxDelay
}
// Add jitter: +/- 25% to avoid thundering herd
jitter := time.Duration(rand.Int63n(int64(delay) / 2))
return delay/2 + jitter
}
// isTransient classifies retryable SQL Server errors.
// For a fuller example, see "Classify errors as transient or permanent" earlier in this article.
func isTransient(err error) bool {
var mssqlErr mssql.Error
if !errors.As(err, &mssqlErr) {
return errors.Is(err, context.DeadlineExceeded)
}
switch mssqlErr.Number {
case 1205, 40197, 40501, 40613, 49918, 49919, 49920:
return true
}
return mssqlErr.Class >= 17 && mssqlErr.Class <= 19
}
// getEmployeeCount wraps a query with automatic retry.
func getEmployeeCount(ctx context.Context, db *sql.DB) (int, error) {
var count int
err := RetryFunc(ctx, DefaultRetryConfig, func(ctx context.Context) error {
// This query executes on every retry attempt until success or exhaustion.
return db.QueryRowContext(ctx, "SELECT COUNT(*) FROM HumanResources.Employee").Scan(&count)
})
return count, err
}
// Example call site (assumes db is already initialized).
func example(ctx context.Context, db *sql.DB) {
queryCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
defer cancel()
count, err := getEmployeeCount(queryCtx, db)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Employee count: %d\n", count)
}
Holtpontok kezelése
A holtpontok (hiba 1205) a leggyakoribb átmeneti hibák többfelhasználós alkalmazásokban. Az SQL Server automatikusan megszakítja az egyik ütköző munkamenetet, és a 1205-ös hibát adja vissza az áldozatként kijelölt munkamenetnek.
Patthelyzet észlelése
Ellenőrizd, hogy egy SQL Server hiba holtpont-e (hiba 1205).
func isDeadlock(err error) bool {
var mssqlErr mssql.Error
if errors.As(err, &mssqlErr) {
return mssqlErr.Number == 1205
}
return false
}
Tranzakciók újrapróbálása holtpontok után
Ha holtpont keletkezik egy tranzakción belül, a szerver visszahúzza az egész tranzakciót. Újra kell próbálnod a teljes tranzakciót, nem csak a sikertelen kijelentést:
func transferInventory(ctx context.Context, db *sql.DB, productID, fromLocationID, toLocationID int, qty int) error {
return RetryFunc(ctx, DefaultRetryConfig, func(ctx context.Context) error {
tx, err := db.BeginTx(ctx, &sql.TxOptions{
Isolation: sql.LevelReadCommitted,
})
if err != nil {
return err
}
defer tx.Rollback()
_, err = tx.ExecContext(ctx,
"UPDATE Production.ProductInventory SET Quantity = Quantity - @qty WHERE ProductID = @pid AND LocationID = @lid",
sql.Named("qty", qty),
sql.Named("pid", productID),
sql.Named("lid", fromLocationID))
if err != nil {
return err
}
_, err = tx.ExecContext(ctx,
"UPDATE Production.ProductInventory SET Quantity = Quantity + @qty WHERE ProductID = @pid AND LocationID = @lid",
sql.Named("qty", qty),
sql.Named("pid", productID),
sql.Named("lid", toLocationID))
if err != nil {
return err
}
return tx.Commit()
})
}
Tip
Csökkentse a holtpontokat azzal, hogy minden tranzakció során következetes sorrendben ér el a táblákat, és röviden tartja a tranzakciókat.
Az újrapróbálás helyes válasz az alkalmazáskódban, de ugyanazon lekérdezésen ismételt holtpont esetén tervezési problémát jeleznek. Használd az SQL Server holtpontgráfját (amelyet az Extended Events vagy a system_health munkamenet rögzít) a versengő utasítások és zárolási típusok azonosításához. A holthelyzetek elemzésének és megelőzésének teljes áttekintéséért lásd a Deadlocks útmutatót. A tranzakciókra jellemző holthelyzetkezelési stratégiákról lásd: Deadlock kezelés.
A kapcsolatkészlet kimerülésének kezelése
Amikor a poolban lévő összes kapcsolat használatban van, és elérik a MaxOpenConns értéket, az új hívók várakoznak, amíg egy kapcsolat elérhetővé nem válik, vagy le nem jár a kontextus határideje. Ez a helyzet lassú kérések vagy kontextus-határidő túllépési hibák formájában nyilvánul meg, nem pedig közvetlen poolkimerülési hibákként.
Medencenyomás érzékelése
Figyeld a pool statisztikákat, és jelezd, ha nő a várakakozási szám.
func monitorPool(ctx context.Context, db *sql.DB) {
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
var lastWaitCount int64
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
stats := db.Stats()
newWaits := stats.WaitCount - lastWaitCount
lastWaitCount = stats.WaitCount
if newWaits > 0 {
log.Printf("Pool pressure: open=%d inUse=%d idle=%d newWaits=%d waitDuration=%v",
stats.OpenConnections, stats.InUse, stats.Idle,
newWaits, stats.WaitDuration)
}
}
}
}
Gyakori okok és megoldások
| Hibajelenség | A probléma oka | Solution |
|---|---|---|
WaitCount folyamatosan növekszik |
MaxOpenConns túl alacsony |
Növeld MaxOpenConns értékét, hogy megfeleljen az egyidejűségnek. |
InUse hosszabb ideig egyenlő MaxOpenConns értékével |
A csatlakozások nem kerülnek vissza a medencébe | Zárd be *sql.Rows-t, hajtsd végre vagy vond vissza *sql.Tx-et, és azonnal zárd be *sql.Conn-t. |
OpenConnections Folyamatosan nőnek |
A kapcsolatok gyorsabban szivárognak el, mint ahogy a MaxIdleConns újra tudná hasznosítani őket. |
Állítsa be a ConnMaxLifetime és ConnMaxIdleTime értékét a kapcsolat élettartamának korlátozásához. |
| A kontextus határideje túllépett a lekérdezések során | A medence telített, és a hívók túl sokáig várnak | Növelje a pool méretét, csökkentse a lekérdezés végrehajtási idejét, vagy adjon hozzá lekérdezési időtúlolásokat. |
Konkrét SQL Server-hibák kezelése
Korlátozások megsértése
Az egyedi kulcs- és idegen kulcsok megsértése tartós hibák, amelyek logikai problémát jeleznek az alkalmazásban:
func isUniqueViolation(err error) bool {
var mssqlErr mssql.Error
if errors.As(err, &mssqlErr) {
return mssqlErr.Number == 2627 || // Unique constraint violation
mssqlErr.Number == 2601 // Unique index violation
}
return false
}
func isForeignKeyViolation(err error) bool {
var mssqlErr mssql.Error
if errors.As(err, &mssqlErr) {
return mssqlErr.Number == 547 // FK constraint violation
}
return false
}
Felfelé irányuló minta konfliktusészleléssel
Használj utasítást MERGE egy sor atomiszerű beillesztésére vagy frissítésére:
func upsertDepartment(ctx context.Context, db *sql.DB, id int, name, groupName string) error {
_, err := db.ExecContext(ctx, `
MERGE INTO HumanResources.Department AS target
USING (SELECT @id AS DepartmentID, @name AS Name, @grp AS GroupName) AS source
ON target.DepartmentID = source.DepartmentID
WHEN MATCHED THEN
UPDATE SET Name = source.Name, GroupName = source.GroupName
WHEN NOT MATCHED THEN
INSERT (Name, GroupName) VALUES (source.Name, source.GroupName);`,
sql.Named("id", id),
sql.Named("name", name),
sql.Named("grp", groupName))
return err
}
Jogosultsági hibák
Azonosítsa a gyakori engedély nélküli hibaszámokat, hogy világos üzenetet biztosítson a hívóknak:
func isPermissionError(err error) bool {
var mssqlErr mssql.Error
if errors.As(err, &mssqlErr) {
return mssqlErr.Number == 229 || // SELECT permission denied
mssqlErr.Number == 230 || // Column permission denied
mssqlErr.Number == 262 || // CREATE permission denied
mssqlErr.Number == 300 || // VIEW permission denied
mssqlErr.Number == 15247 // User doesn't have permission
}
return false
}
Kezeld a(z) sql.ErrNoRows hibát.
sql.ErrNoRowsnem SQL Server hiba. A QueryRowContext.Scan metódus akkor adja vissza, ha a lekérdezés nem ad sorokat. Kezeld ezt kifejezetten úgy, hogy meg lehessen különböztetni a „not found” állapotot a valódi hibáktól:
func getEmployee(ctx context.Context, db *sql.DB, id int) (*Employee, error) {
var emp Employee
err := db.QueryRowContext(ctx,
"SELECT TOP (1) BusinessEntityID, FirstName + ' ' + LastName AS Name, CountryRegionName AS Location FROM Sales.vSalesPerson WHERE BusinessEntityID = @p1",
sql.Named("p1", id)).Scan(&emp.Id, &emp.Name, &emp.Location)
if errors.Is(err, sql.ErrNoRows) {
return nil, nil // Not found, not an error.
}
if err != nil {
return nil, fmt.Errorf("query employee %d: %w", id, err)
}
return &emp, nil
}
Csomagolási hibák kontextussal
Adjon kontextust a hibákhoz, hogy a hívók megértsék, hol történt a hiba:
func getEmployeesByLocation(ctx context.Context, db *sql.DB, location string) ([]Employee, error) {
rows, err := db.QueryContext(ctx,
"SELECT BusinessEntityID, FirstName + ' ' + LastName AS Name, CountryRegionName AS Location FROM Sales.vSalesPerson WHERE CountryRegionName = @p1",
sql.Named("p1", location))
if err != nil {
return nil, fmt.Errorf("query employees by location %q: %w", location, err)
}
defer rows.Close()
var employees []Employee
for rows.Next() {
var emp Employee
if err := rows.Scan(&emp.Id, &emp.Name, &emp.Location); err != nil {
return nil, fmt.Errorf("scan employee row: %w", err)
}
employees = append(employees, emp)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("iterate employee rows: %w", err)
}
return employees, nil
}
A(z) %w használata megőrzi a hibaláncot, így a hívók továbbra is használhatják a(z) errors.As és errors.Is elemeket a mögöttes hiba ellenőrzésére.
Hibakezelési ellenőrzőlista
| Area | Recommendation |
|---|---|
| Típusassertálás | Deklaráld var mssqlErr mssql.Error, majd használd errors.As(err, &mssqlErr) az SQL Server hibamezők eléréséhez. |
| Átmeneti észlelés | Sorolj hibákat szám és súlyosság szerint, mielőtt eldöntenéd, hogy újra próbálkoznak-e. |
| Újrapróbálkozás logikája | Exponenciális visszalépés használata jitterrel. Állíts be maximális próbálkozásszámot és az általános időkorlátot a kontextus alapján. |
| Deadlocks | Próbáld meg újra az egész tranzakciót, nem az egyéni kimutatásokat. Csökkentsd a holtpontokat azzal, hogy következetesen hozzáférsz a táblákhoz. |
| Medence kimerülése | Figyeld db.Stats() és állíts be kontextushatárokat minden adatbázis-hívásnál. |
| ErrNoRows | A(z) QueryRowContext esetén kezelje explicit módon a(z) sql.ErrNoRows elemet. Ez nem szerverhiba. |
| Hibacsomagolás | Használd a fmt.Errorf elemet a %w elemmel együtt, hogy kontextust adj hozzá, miközben megőrzöd a hibaláncot. |
| Korlátozások megsértése | Ellenőrizze a 2627-es, 2601-es (egyedi) és 547-es (idegen kulcs) hibaszámokat, hogy gondosan kezelje az ütközéseket. |