Использование пакетов базы данных/sql и драйверов и Tx не представляется возможным, чтобы определить, была ли транзакция выполнена или откат, не пытаясь повторить попытку и получив ошибку как результат, а затем изучить ошибку, чтобы определить тип ошибки. Я хотел бы иметь возможность определить из объекта Tx, независимо от того, было оно совершено или нет. Конечно, я могу определить и установить другую переменную в функции, которая использует Tx, но у меня их довольно много, и каждый раз это время 2 (переменная и назначение). У меня также есть отложенная функция для выполнения отката, если это необходимо, и ему необходимо передать переменную bool.
Было бы приемлемым, чтобы установить переменную Tx в nil после Commit или Rollback, и GC восстановит любую память, или это нет-нет, или есть лучшая альтернатива?database/sql Tx - обнаружение фиксации или отката
ответ
Зачем вам это нужно? Функция, вызывающая Begin()
, также должна звонить Commit()
или Rollback()
и возвращать соответствующую ошибку.
Например, этот код фиксации или отката в зависимости от того, возвращается ошибка:
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
}
Обратите внимание, как я проверяю error
видеть, должен ли я совершить или откат. Однако вышеприведенный пример не обрабатывает паники.
Мне не нравится делать логику commit/rollback для каждой процедуры базы данных, поэтому я обычно обертываю их обработчиком транзакций. Что-то вдоль линий этого:
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
}
Это позволяет мне сделать это вместо:
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
}
})
}
Обратите внимание, что если что-то в моей транзакции паникует она автоматически обрабатывается обработчиком транзакций.
В моей реальной реализации я передаю интерфейс вместо * sql.Tx, чтобы предотвратить нежелательные вызовы Commit()
или Rollback()
.
Вот простой фрагмент кода, чтобы продемонстрировать, как defer
работы (печать 4, а не 5):
package main
func test() (i int) {
defer func() {
i = 4
}()
return 5
}
func main() {
println(test())
}
хороший ответ! Я думаю, вы пропустили «обратный нуль» в конце вашей второй реализации doSomething(). – splinter123
Люк, как и когда ошибка оценивается? Согласно документации, «err» должен получить свою ценность, когда она впервые объявлена в вызове отсрочки.Поэтому для меня это немного сбивает с толку, так как значение «err», используемое при отсрочке, похоже, меняется. – mirage
err объявляется перед отсрочкой через: = (двоеточие равно). Anon func захватывает его. Отсрочка вызывается непосредственно перед возвратом значения. Это позволяет установить его. Когда происходит паника, он восстанавливается, превращается в ошибку, а затем возвращается. Если ошибка происходит каким-либо образом, происходит откат. Наконец, фиксация происходит, если ошибок нет, а err (в настоящее время nil) установлено значение Commits return в случае его ошибок. – Luke
- 1. Ошибка фиксации MySQL и отката
- 2. TSQL сделки - фиксации и отката
- 3. ARC обнаружение круговой фиксации
- 4. фиксации и отката для определенных случаев
- 5. Поддержка приемника для CMT после фиксации/отката
- 6. выполняет команду «\ copy» команды фиксации и отката в postgres?
- 7. Перфосс отката: депо или папка?
- 8. Обнаружение кода тестового кода объекта фиксации
- 9. Транзакционные обновления, которые применяются к БД независимо от отсутствия фиксации или отката
- 10. Как Oracle обрабатывает SQL, когда autocommit = false и нет фиксации или отката?
- 11. Создайте динамический прокси для подключения jdbc для переопределения методов фиксации или отката
- 12. Hibernate 5 и обнаружение отката транзакции с перехватчиком
- 13. Что делает оператор отката точно?
- 14. Regex: txt vs tx?
- 15. Отката приложений, использующих анзибль или кукольный
- 16. Функция отката pgsql или аннулирование последнего шага
- 17. Функция отката или шаблон проектирования в C++
- 18. ли остановки запроса с гарантией отката отката
- 19. Spring «Префикс« tx »для элемента« tx: annotation-driven »не связан».
- 20. Spring Tx ошибка
- 21. tx: аннотация не работает
- 22. Сбой отката транзакции JDBC при закрытом соединении
- 23. Обнаружение создания ветвей или закладок в HG
- 24. Github Mac Client - нет отката - кнопка недоступна
- 25. python opencv - обнаружение пятен или обнаружение круга
- 26. Спящий режим отката
- 27. Решение для предварительного просмотра пользовательских изменений и разрешения отката/фиксации в течение периода времени
- 28. Сделки фиксации и отката с Entity Framework, Mysql и LINQ к SQL в C#
- 29. Ошибка сети. Метаданные отката
- 30. Сбросить или вернуть Gist в более раннее состояние фиксации, используя веб-интерфейс Github или настольное приложение.
Не уверен, если я понимаю проблему. Вы должны завершить транзакцию с помощью Commit или Rollback, чтобы вы знали, что вы сделали, но вы не хотите помнить об этом в дополнительной переменной? Вы можете обернуть Tx и bool в свой собственный RememberingTx, это уменьшит количество строк. Что касается вопроса GC: не имеет значения, если вы установите нуль или нет: память будет восстановлена, как только ссылка не будет оставлена. Итак: да, вы можете иметь 'var tx * Tx; чик; если cond {tx.Commit; tx = nil} else {tx.Rollback}; чик; если tx == nil {был зачислен} else {был откат} ', но он кажется уродливым. – Volker
Вот что это значит, но есть отложенная функция, которая выполняет откат, если Tx не равен нулю. Как только транзакция будет совершена, Tx не может быть использован в любом случае, поэтому я планирую установить его на нуль. Это не очень, но попытка откат и тестирование сообщения об ошибке тоже не очень. Проблема в том, что AFAIK не может проверить, выполнена ли транзакция из Tx. Я не уверен, почему это было сделано так, возможно, в производительности. –