LoginSignup
14
9

More than 5 years have passed since last update.

GoでMySQLのエラー番号を取得してユニーク制約違反をハンドリングする

Posted at

GoでRDBにアクセスするには標準パッケージのdatabase/sqlを使うわけですが、database/sqlの返すエラーは文字列のエラーメッセージ以上の情報を持っていないので、発生したエラーに応じた処理ということができません。例えばユニーク制約違反をハンドリングしたい場合とか。

エラーメッセージの文字列を見てエラーの種類を判別するということも出来なくはないかもしれませんが、最期の手段にしたいところです。

なにか良い方法ないかなーと検索してみたらこちらのトピックで、ドライバの生成するエラーがdatabase/sqlでラップされないんなら、型アノテーションでエラーを判別できるのでは?というアイデアが挙がっていました。

というわけで、database/sqlのソースを確認してみたところ、ドライバが生成したエラーはラップされずにそのまま返される様子。そして、github.com/go-sql-driver/mysqlにはそのものずばりのmysql.MySQLErrorがあるではないですか。

というわけで試してみました。

package main

import (
    "database/sql"
    "log"

    "github.com/go-sql-driver/mysql"
)

func main() {
    // CREATE TABLE test (i INT PRIMARY KEY);

    db, _ := sql.Open("mysql", "foobar")

    db.Exec("INSERT INTO test VALUES (1)")

    _, err := db.Exec("INSERT INTO test VALUES (1)")
    if err != nil {
        if mysqlErr, ok := err.(*mysql.MySQLError); ok {
            log.Printf("Number: %d", mysqlErr.Number)
            log.Printf("Message: %s", mysqlErr.Message)
            log.Printf("Error(): %s", mysqlErr.Error())
        }
    }
}

実行結果

$ go run main.go
2016/06/20 23:55:57 Number: 1062
2016/06/20 23:55:57 Message: Duplicate entry '1' for key 'PRIMARY'
2016/06/20 23:55:57 Error(): Error 1062: Duplicate entry '1' for key 'PRIMARY'

いけました。NumberフィールドにMySQLのエラーコードMessageフィールドにMySQLのエラーメッセージが入れられているようです。MySQLプロトコルのエラーパケットから取り出された情報のようですね。SQLSTATEに関してはMySQLErrorには含まれないようです

これで詳細なエラー原因を判別することができそうですね。おそらくは保証された動作ではないでしょうから、そこには注意が必要そうですが、文字列で判別するよりは幾分ましかなと。

14
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
9