トランザクションを使う

ツイート このエントリーをはてなブックマークに追加
1つ上へ / ブログトップへ

トランザクションは、トランザクションオブジェクトを生成して使います。

今回の例では、id列をprimary keyにしています。また、前回のINSERTを実行し、id=123のレコードを既に登録済みにしています。

package main

import (
        "database/sql"
        "fmt"
        "github.com/go-sql-driver/mysql"
)

func main() {
        db, err := sql.Open("mysql", "gotest:gotest@/demo")
        if err != nil {
                fmt.Printf("Failed to connect")
                return
        }
        defer db.Close()

        tr, err := db.Begin()
        if err != nil {
                fmt.Printf("Failed to begin transaction : %s", err)
                return
        }

        statement, err := tr.Prepare("INSERT INTO user(id,email) VALUES(?,?)")
        if err != nil {
                fmt.Printf("Failed to prepare : %s", err)
                tr.Rollback()
                return
        }
        defer statement.Close()

        if !insert("124", "demo@fkmsoft.jp", statement) {
                tr.Rollback()
                return
        }
        fmt.Printf("created! 124/demo@fkmsoft.jp\n")
        if !insert("123", "demo@fkmsoft.jp", statement) {
                tr.Rollback()
                return
        }
        fmt.Printf("created! 123/demo@fkmsoft.jp\n")
        tr.Commit()
}

func insert(id, email string, statement *sql.Stmt) bool {
        _, err := statement.Exec(id, email)
        if err != nil {
                if err2, ok := err.(*mysql.MySQLError); ok {
                        fmt.Printf("Failed to execute Query : %s Number=%d", er\
r, err2.Number)
                } else {
                        fmt.Printf("Failed to execute Query : %s", err, err)
                }
                return false
        }
        return true
}

ポイントだけ見ていきましょう。

tr, err := db.Begin()
if err != nil {
        fmt.Printf("Failed to begin transaction : %s", err)
        return
}

Begin()メソッドでトランザクションオブジェクトを生成します。End()は無いので注意。

statement, err := tr.Prepare("INSERT INTO user(id,email) VALUES(?,?)")
if err != nil {
        fmt.Printf("Failed to prepare : %s", err)
        tr.Rollback()
        return
}
defer statement.Close()

TxのPrepare()メソッドでStmtを作ります。dbがTxに変わっただけですね。

Stmtを作った後は同じです。最後にコミット/ロールバック

成功した時はCommit()メソッドを呼びます。

tr.Commit()

失敗し、ロールバックしたい時はRollback()メソッドを呼びます。ホントはdeferで呼んだほうがいいかも。

tr.Rollback()

冒頭の条件で実行すると、1行分、成功のメッセージが出た後、エラーメッセージが出てロールバックされます。

1つ上へ / ブログトップへ