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

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

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

*最初に知っておくべきこととして、sql.DBはデータベース接続ではないということです。*
#インポート
以下の二つをインポートして下さい。

```
• "database/sql"

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

```golang
sql.Open("mysql", "ユーザ名:パスワード@tcp(ホスト名:ポート番号)/データベース名")
//通常：ポート番号３３０６(筆者はMAMPでのデータベースサーバを使っているためポート番号8889)
```
**＊database/sqlの操作には常にエラー処理が必要**

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

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

```golang: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(&⒈の変数, ・・・)**でカラムを変数を読み込んでいく

```golang: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(パラメータ)**する。

```golang: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(パラメータ)**で実行。

```golang: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()**。

```golang:sql.go
tr, err := db.Bigin()
if err != nil {
   //エラー
}
//この下からエラーに入るたびに
tr.Rollback()
//成功すれば
tr.Commit()
```
以上。
もし何か間違っている等のご指摘があればご連絡ください。
最後まで読んで頂きありがとうございました。
次回はまだ未定ですが多分「Go言語を真剣に勉強してみた〜WEBアプリケーション開発編〜」かな？？？