Utilizzando i pacchetti database/sql e driver e Tx, non è possibile che venga rilevato se una transazione è stata eseguita o rollback senza tentare un altro e ricevere un errore come risultato e quindi esaminare l'errore per determinare il tipo di errore. Mi piacerebbe essere in grado di determinare dall'oggetto Tx se commesso o meno. Certo, posso definire e impostare un'altra variabile nella funzione che utilizza Tx, ma ne ho un bel numero, ed è volta 2 ogni volta (variabile e assegnazione). Ho anche una funzione differita per fare un rollback, se necessario, e deve essere passato la variabile bool.
Sarebbe accettabile impostare la variabile Tx su nil dopo un commit o rollback, e il GC recupererà la memoria, o è un no-no, o c'è un'alternativa migliore?database/sql Tx - rilevamento Commit o rollback
risposta
Perché dovresti averne bisogno? La funzione che chiama Begin()
dovrebbe anche chiamare Commit()
o Rollback()
e restituire un errore appropriato.
Ad esempio, questo codice fa un commit o rollback a seconda se viene restituito un errore:
func (s Service) DoSomething() (err error) {
tx, err := s.db.Begin()
if err != nil {
return
}
defer func() {
if err != nil {
tx.Rollback()
return
}
err = tx.Commit()
}()
if _, err = tx.Exec(...); err != nil {
return
}
if _, err = tx.Exec(...); err != nil {
return
}
// ...
return
}
Notate come sto controllando error
per vedere se o non dovrei commit o rollback. L'esempio sopra non, tuttavia, gestisce il panico.
Non mi piace eseguire la logica di commit/rollback su ogni routine di database, quindi di solito li incorporo in un gestore di transazioni. Qualcosa sulla falsariga di questo:
func Transact(db *sql.DB, txFunc func(*sql.Tx) error) (err error) {
tx, err := db.Begin()
if err != nil {
return
}
defer func() {
if p := recover(); p != nil {
tx.Rollback()
panic(p) // re-throw panic after Rollback
} else if err != nil {
tx.Rollback()
} else {
err = tx.Commit()
}
}()
err = txFunc(tx)
return err
}
Questo mi permette di fare questo, invece:
func (s Service) DoSomething() error {
return Transact(s.db, func (tx *sql.Tx) error {
if _, err := tx.Exec(...); err != nil {
return err
}
if _, err := tx.Exec(...); err != nil {
return err
}
})
}
Si noti che se qualcosa dentro la mia transazione panico è gestito automaticamente dal gestore delle transazioni.
Nella mia implementazione effettiva passaggio un'interfaccia invece di * sql.Tx per impedire chiamate indesiderate a Commit()
o Rollback()
.
Ecco un semplice frammento di dimostrare come defer
opere (stampe 4, non 5):
package main
func test() (i int) {
defer func() {
i = 4
}()
return 5
}
func main() {
println(test())
}
bella risposta! Penso che ti sia mancato un "return nil" verso la fine della tua seconda implementazione doSomething(). – splinter123
Luke, come e quando viene valutato err? Secondo la documentazione, "err" dovrebbe ottenere il suo valore quando viene dichiarato per la prima volta nella chiamata differita.Quindi questo è in realtà un po 'di confusione per me, dal momento che il valore di "err", come usato in differimento, sembra cambiare. – mirage
err viene dichiarato prima del differimento tramite: = (due punti uguali). L'anon func lo cattura. Il rinvio è chiamato appena prima che il valore venga restituito. Questo gli permette di essere impostato. Quando si verifica un panico viene recuperato, trasformato in errore, quindi restituito. Se si verifica un errore in qualsiasi modo, si verifica un rollback. Finalmente un commit avviene se non ci sono errori e err (attualmente nil) è impostato su Commits valore di ritorno nel caso in cui errori. – Luke
- 1. Come usare Rollback/Commit in Oracle SQL
- 2. Transazioni Oracle di commit e rollback
- 3. salva il commit rollback in mysql
- 4. COMMIT O conn.setAutoCommit (true)
- 5. JavaConfig: Sostituzione AOP: consigliere e tx: consigli
- 6. SQL Server BEGIN/END vs BEGIN TRANS/COMMIT/ROLLBACK
- 7. EF5 DbContext.SaveChanges gestisce il commit e il rollback delle transazioni?
- 8. Transazione di rollback dopo il commit nelle guide
- 9. DbContextTransaction rollback
- 10. transazione conteggio dopo EXECUTE indica che una dichiarazione COMMIT o ROLLBACK TRANSACTION manca - SQL server 2005
- 11. Come eseguire il rollback o il commit di una transazione in SQL Server
- 12. rollback più commit (prima spinto al pubblico) in Mercurial
- 13. Un rollback all'interno di un INSERT DOPO o UPDATE DOPO innesca il rollback dell'intera transazione
- 14. Differenza tra tx e rx?
- 15. Come uccidere o eseguire il rollback della transazione attiva?
- 16. rollback un Git merge
- 17. Spring "Il prefisso" tx "per l'elemento" tx: annotation-driven "non è associato."
- 18. equivalente git per rollback hg
- 19. Rilevamento ambiente: node.js o browser
- 20. rollback dopo l'errore nella transazione
- 21. commit-pull-merge-push o pull-merge-commit-push?
- 22. È richiesta la ROLLBACK TRANSACTION?
- 23. Java: commit vs rollback contro nulla quando la semantica è invariata?
- 24. Utente Oracle disconnesso senza commit/rollback, non più può cambiare database
- 25. SQLAlchemy Errore di rollback annidato
- 26. Come implementate glOrtho per opengles 2.0? Con o senza tx, ty, tz valori dalle specifiche glOrtho?
- 27. MySql stored procedure, transazioni e rollback
- 28. È possibile utilizzare il rollback TransactionScope con selenio o Watin?
- 29. Rilevamento di immissione su QLineEdit o QPushButton
- 30. Impossibile eseguire il rollback, connessione chiusa
Non sono sicuro se ho ben capito il problema. Devi terminare una transazione con Commit o Rollback in modo da sapere cosa hai fatto ma non vuoi ricordarlo in una variabile extra? Potresti avvolgere Tx e il bool nel tuo RememberingTx, questo ridurrebbe un po 'il conteggio delle righe. Per quanto riguarda la domanda GC: Non importa se si imposta a zero o no: la memoria verrà recuperata una volta che non vi è più alcun riferimento. Quindi: Sì, puoi avere 'var tx * Tx; snip; se cond {tx.Commit; tx = nil} else {tx.Rollback}; snip; se tx == nil {era commited} else {was rollbacked} 'ma sembra brutto. – Volker
Ecco di cosa si tratta, ma esiste una funzione differita che esegue un rollback se Tx non è nullo. Una volta che una transazione è stata commessa, il Tx non può essere comunque utilizzato, quindi ho intenzione di impostarlo su zero. Non è bello, tuttavia tentare un rollback e testare il messaggio di errore non è carino. Il problema è che AFAIK non ha modo di testare se la transazione è "conclusa" da Tx. Non sono sicuro del motivo per cui è stato fatto in quel modo, forse le prestazioni. –