база данных / sql Tx - обнаружение фиксации или отката

Это работает для извлечения каталога сборки, из которого мы можем определить местоположение bin.

var location = System.Reflection.Assembly.GetEntryAssembly().Location;
var directory = System.IO.Path.GetDirectoryName(location);
System.Console.WriteLine(directory);

Выход

C:\MyApplication\bin\Debug\netcoreapp1.0
29
задан Nicolas Kaiser 24 April 2013 в 07:54
поделиться

1 ответ

Вы хотите убедиться, что Begin(), Commit() и Rollback() появляются в одной и той же функции. Это облегчает отслеживание транзакций и позволяет вам гарантировать их правильное закрытие с помощью defer.

Вот пример этого, который делает 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
}

Это может стать немного повторяющимся. Еще один способ сделать это - обернуть ваши транзакции с помощью обработчика транзакций:

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() // err is non-nil; don't change it
        } else {
            err = tx.Commit() // err is nil; if Commit returns error update err
        }
    }()
    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
        }
        return nil
    })
}

. обеспечивает правильную обработку транзакций.

В моем обработчике транзакций я использую recover(), чтобы поймать панику, чтобы убедиться, что откат происходит немедленно. Я повторно выбрасываю панику, чтобы позволить моему коду перехватить ее, если ожидается паника. При нормальных обстоятельствах паника не должна возникать. Вместо этого должны быть возвращены ошибки.

Если бы мы не справились с паникой, транзакция в конце концов была бы отменена. Неподтвержденная транзакция откатывается базой данных, когда клиент отключается или когда транзакция получает сборщик мусора. Однако ожидание самостоятельного разрешения транзакции может вызвать другие (неопределенные) проблемы. Так что лучше решить это как можно быстрее.

Одна вещь, которая может быть не сразу понятна, это то, что defer может изменить возвращаемое значение в замыкании, если возвращаемая переменная захвачена. В обработчике транзакции транзакция фиксируется, когда err (возвращаемое значение) равно нулю. Вызов Commit также может вернуть ошибку, поэтому мы устанавливаем его возвращение на err с помощью err = tx.Commit(). Мы не делаем то же самое с Rollback, потому что err не ноль, и мы не хотим перезаписывать существующую ошибку.

110
ответ дан ZeissS 24 April 2013 в 07:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: