LoginSignup
2
2

More than 5 years have passed since last update.

Go言語を真剣に勉強してみた〜データベース接続(MySQL)編〜

Last updated at Posted at 2018-09-30

はじめに

こんにちは。某学校でプログラミング等の勉強中のサーバーサイドのプログラマーのワタタクです。:relaxed:
さて今回は「Go言語を真剣に勉強してみた〜データベース接続(MySQL)編〜」と言うことで「Goでのデータベースについての扱い方」について見ていきましょう。
では、早速いってみましょう:point_up:
「Go言語を真剣に勉強してみた〜基本構文編①(変数、定数、条件分岐、繰り返し処理)〜」についてはこちらから。
「Go言語を真剣に勉強してみた〜基本構文編②(配列)〜」についてはこちらから。
「Go言語を真剣に勉強してみた〜基本構文編③(関数)〜」についてはこちらから。
「Go言語を真剣に勉強してみた〜基本構文編④(ポインタ、構造体)〜」についてはこちらから。
「Go言語を真剣に勉強してみた〜パッケージ編〜」についてはこちらから。

概要

Go言語でデータベースにアクセスするには、sql.DBを使います。この型を使用することで、ステートメントやトランザクションを生成し、クエリを実行し、結果を取得することができます。

最初に知っておくべきこととして、sql.DBはデータベース接続ではないということです。

インポート

以下の二つをインポートして下さい。

• "database/sql"

• _ "github.com/go-sql-driver/mysql"

ドライバをブランクインポートしていることに注意してください。
パッケージ修飾子を_へとエイリアスすることで、あなたのコードからはエクスポートされた名前は見えません。
その中では、ドライバがdatabase/sqlパッケージに対して自身を利用可能として登録します。しかし通常は他には何も起こりません。

データベースアクセス

sql.Open("mysql", "ユーザ名:パスワード@tcp(ホスト名:ポート番号)/データベース名")
//通常:ポート番号3306(筆者はMAMPでのデータベースサーバを使っているためポート番号8889)

*database/sqlの操作には常にエラー処理が必要

データベースが利用可能でアクセス可能かどうか、すぐに確認したい場合はdb.Ping()を使ってください。その際はエラーチェックを忘れないでください。

作業終了後には、データベースを Close()するのが普通。
*defer:特定の処理を関数の一番最後に実行することができます。=遅延実行

sql.go
db, err := sql.Open("mysql", "scott:tiger@tcp(127.0.0.1:8889)/wp32scott")
if err != nil {
    log.Fatal(err)
}

err = db.Ping()
if err != nil {
    fmt.Println("データベース接続失敗")
}

defer db.Close()

参照系(SELECT)

全件処理

⒈テーブルのカラム名の変数をすべて用意。(構造体を作ってもよい)
db.Query("SELECT文")でクエリーを送信。
⒊⒉の戻り値をClose()する。
⒋⒉の戻り値のNext()を使って、行セットに対して繰り返し処理する。
⒌各行において⒉の戻り値のScan(&⒈の変数, ・・・)でカラムを変数を読み込んでいく

sql.go
var (
    deptno int
    dname string
    loc string
)

rows, err := db.Query("SELECT * FROM dept")
if err != nil {
    log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
    err := rows.Scan(&deptno, &dname, &loc)
    if err != nil {
    log.Fatal(err)
    }
    //結果
    fmt.Println(deptno, dname, loc)
}

主キー検索

⒈テーブルのカラム名の変数をすべて用意。(構造体を作ってもよい)
db.Prepare("SELECT文")でSQL発行
⒊⒉の戻り値をQueryRow(パラメータ)する。

sql.go
var (
    deptno int
    dname string
    loc string
)
stmt, err := db.Prepare("SELECT * FROM dept WHERE deptno = ?")
if err != nil {
    log.Fatal(err)
}
err = stmt.QueryRow(10).Scan(&deptno, &dname, &loc)
if err != nil {
    log.Fatal(err)
}
fmt.Println(deptno, dname, loc)

更新系(INSERT,UPDATE,DELETE)

db.Prepare("INSERT,UPDATE,DELETE文")でSQL発行
⒉⒈の戻り値のExec(パラメータ)で実行。

sql.go
/*
 *INSERT
 */
stmt, err := db.Prepare("INSERT INTO dept(deptno, dname, loc) VALUES(?, ?, ?)")
if err != nil {
   log.Fatal(err)
}
res, err := stmt.Exec(50, "WATATAKU", "JAPAN")
if err != nil {
    log.Fatal(err)
}
rowCnt, err := res.RowsAffected()  // 影響を受けた行数
if err != nil {
    log.Fatal(err)
}
log.Printf("%d件追加しました", rowCnt)

/*
 *UPDATE
 */
stmt, err := db.Prepare("UPDATE dept SET dname=?,loc=? WHERE deptno=?")
if err != nil {
    log.Fatal(err)
}
res, err := stmt.Exec("KAWAAI", "KORIA", 50)
if err != nil {
    log.Fatal(err)
}
rowCnt, err := res.RowsAffected()  // 影響を受けた行数
if err != nil {
    log.Fatal(err)
}
log.Printf("%d件更新しました", rowCnt)

/*
 *DELETE
 */
stmt, err := db.Prepare("DELETE FROM dept WHERE deptno=?")
if err != nil {
    log.Fatal(err)
}
res, err := stmt.Exec(50)
if err != nil {
    log.Fatal(err)
}
rowCnt, err := res.RowsAffected()  // 影響を受けた行数
if err != nil {
    log.Fatal(err)
}
log.Printf("%d件削除しました", rowCnt)

トランザクション

SQL発行前にBigin()し、各エラーに入るたびにRollback()成功すればCommit()

sql.go
tr, err := db.Bigin()
if err != nil {
   //エラー
}
//この下からエラーに入るたびに
tr.Rollback()
//成功すれば
tr.Commit()

以上。
もし何か間違っている等のご指摘があればご連絡ください。
最後まで読んで頂きありがとうございました。
次回はまだ未定ですが多分「Go言語を真剣に勉強してみた〜WEBアプリケーション開発編〜」かな???

2
2
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
2
2