Транзакции Raw sql с подготовленными инструкциями golang
у меня возникли проблемы с поиском некоторых примеров, которые делают три из следующих вещей:
1) разрешить необработанные транзакции sql в golang.
2) использовать подготовленные операторы.
3) откат при сбое запросов.
Я хотел бы сделать что-то подобное, но с готовыми заявлениями.
stmt, stmt_err := db.Prepare(`
BEGIN TRANSACTION;
-- Insert record into first table.
INSERT INTO table_1 (
thing_1,
whatever)
VALUES(,);
-- Inert record into second table.
INSERT INTO table_2 (
thing_2,
whatever)
VALUES(,);
END TRANSACTION;
`)
if stmt_err != nil {
return stmt_err
}
res, res_err := stmt.Exec(
thing_1,
whatever,
thing_2,
whatever)
когда я запускаю это, я получаю эту ошибку:
pq: cannot insert multiple commands into a prepared statement
что это дает? Возможны ли транзакции, совместимые с ACID, в golang? Я не могу найти пример.
изменить нет примеров здесь.
2 ответов
Yes Go имеет отличную реализацию sql сделки. Мы начинаем транзакцию с db.Начать и мы можем закончить его с tx.Commit если все пойдет хорошо или с tx.Откат в случае ошибки.
введите TX struct { }
Tx-это незавершенная транзакция базы данных.
транзакция должна завершиться вызовом для фиксации или отката.
после вызова Фиксация или откат, все операции транзакции завершаются с ошибкой ErrTxDone.
операторы, подготовленные для транзакции путем вызова методов Prepare или Stmt транзакции, закрываются вызовом Commit или Rollback.
также обратите внимание, что мы готовим запросы с переменной транзакции tx.Готовиться.(..)
ваша функция может выглядеть так:
func doubleInsert(db *sql.DB) error {
tx, err := db.Begin()
if err != nil {
return err
}
{
stmt, err := tx.Prepare(`INSERT INTO table_1 (thing_1, whatever)
VALUES(,);`)
if err != nil {
tx.Rollback()
return err
}
defer stmt.Close()
if _, err := stmt.Exec(thing_1, whatever); err != nil {
tx.Rollback() // return an error too, we may want to wrap them
return err
}
}
{
stmt, err := tx.Prepare(`INSERT INTO table_2 (thing_2, whatever)
VALUES(, );`)
if err != nil {
tx.Rollback()
return err
}
defer stmt.Close()
if _, err := stmt.Exec(thing_2, whatever); err != nil {
tx.Rollback() // return an error too, we may want to wrap them
return err
}
}
return tx.Commit()
}
у меня есть полный пример здесь
Я придумал возможное решение для отката при любом сбое без каких-либо существенных недостатков. Я довольно, хотя Golang новый, я могу ошибаться.
func CloseTransaction(tx *sql.Tx, commit *bool) {
if *commit {
log.Println("Commit sql transaction")
if err := tx.Commit(); err != nil {
log.Panic(err)
}
} else {
log.Println("Rollback sql transcation")
if err := tx.Rollback(); err != nil {
log.Panic(err)
}
}
}
func MultipleSqlQuriesWithTx(db *sql.DB, .. /* some parameter(s) */) (.. .. /* some named return parameter(s) */, err error) {
tx, err := db.Begin()
if err != nil {
return
}
commitTx := false
defer CloseTransaction(tx, &commitTx)
// First sql query
stmt, err := tx.Prepare(..) // some raw sql
if err != nil {
return
}
defer stmt.Close()
res, err := stmt.Exec(..) // some var args
if err != nil {
return
}
// Second sql query
stmt, err := tx.Prepare(..) // some raw sql
if err != nil {
return
}
defer stmt.Close()
res, err := stmt.Exec(..) // some var args
if err != nil {
return
}
/*
more tx sql statements and queries here
*/
// success, commit and return result
commitTx = true
return
}