次の3つを実行する例を見つけるのに苦労しています。
1)golangで生のSQLトランザクションを許可します。
2)準備されたステートメントを使用します。
3)クエリ失敗時のロールバック。
私はこのようなことをしたいのですが、準備されたステートメントを使用します。
stmt, stmt_err := db.Prepare(`
BEGIN TRANSACTION;
-- Insert record into first table.
INSERT INTO table_1 (
thing_1,
whatever)
VALUES($1,$2);
-- Inert record into second table.
INSERT INTO table_2 (
thing_2,
whatever)
VALUES($3,$4);
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でも可能ですか?例が見つかりません。
例を編集しない ここ 。
はいGoはsql transactions の優れた実装を備えています。 db.Begin でトランザクションを開始し、すべてがうまくいけば tx.Commit で、または tx.Rollback でトランザクションを終了できます。エラー。
タイプTx構造体{}
Txは進行中のデータベーストランザクションです。
トランザクションは、コミットまたはロールバックの呼び出しで終了する必要があります。
CommitまたはRollbackを呼び出した後、トランザクションのすべての操作がErrTxDoneで失敗します。
トランザクションのPrepareまたはStmtメソッドを呼び出してトランザクション用に準備されたステートメントは、CommitまたはRollbackの呼び出しによって閉じられます。
また、トランザクション変数tx.Prepare(...)を使用してクエリを準備することにも注意してください。
関数は次のようになります。
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($1,$2);`)
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($1, $2);`)
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
}