我无法找到一些可以执行以下三项操作的示例:
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
是什么给出的?是否可以在golang中进行符合ACID的交易?我找不到一个例子。
EDIT 没有例子here。
答案 0 :(得分:13)
是Go有一个很好的sql transactions实现。我们使用db.Begin启动交易,如果一切顺利,我们可以使用tx.Commit结束,如果出现错误,我们可以使用tx.Rollback结束。
输入Tx struct {}
Tx是正在进行的数据库事务。
事务必须以对Commit或Rollback的调用结束。
在调用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()
}
我有一个完整的示例here
答案 1 :(得分:0)
我想出了一个可能的解决方案,可以在没有任何明显缺陷的情况下回滚任何故障。我对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
}