"BOKU"のITな日常

興味のむくまま気の向くままに調べたり・まとめたりしてます。

GO言語(golang)/データベース(MariaDB・MySQL)を使う(2)/sqlxでトランザクション処理

 f:id:arakan_no_boku:20210412005751p:plain

目次

今回sqlxを使ってやることの整理

Go言語でトランザクション処理をやります。

DBはMariaDBMySQL)で、DBはインストールしてある前提です。

環境はWindows10/VSCodeを使ってます。

MySQLドライバのインストールなどを(1)で行った続きになります。

前回は、DBの操作は、「 database/sql」を使いましたが、Selectの結果を構造体で受けられないなど、使い勝手が悪いので、今回はその拡張版である「sqlx」を使います。 

github.com

sqlxを使うには、go getでインストールして

go get github.com/jmoiron/sqlx

以下をインポートします。

"github.com/jmoiron/sqlx"

とりあえず、あれこれ欲張ってもしょうがないので、今回は以下の3つだけやります。

  • sqlxでデータベースオープンする
  • sqlxでトランザクション内で更新系(insert、update、delete)を実行する 
  • sqlxでSelect文でデータを取得して構造化データに結果を格納する

やり方を確認します。

sqlxでデータベースオープンする

データベースオープンは、前回の「 database/sql」の時とほぼ同じやり方です。

構文

dbx, err := sqlx.Open("mysql", "user_id:password@tcp(localhost:3306)/dbname")

引数は

  • user_id:DBユーザID
  • password:DBパスワード
  • @tcp(localhost:3306):@プロトコル(host:port)
  • dbname:データベース名

ですので、環境にあわせて変更します。

sqlxでトランザクション内で更新系(insert、update、delete)を実行する 

上記のようにオープンした「dbx」があるとすると。

1.トランザクションを開始する。

tx := dbx.MustBegin()

2. トランザクション内でSQLを実行する。

tx.MustExec("insert into gotest values(?,?)", id, name+strconv.Itoa(id))

tx.MustExec("update gotest set name=? where id < 5", "IDが5より小さい")

tx.MustExec("delete from gotest")

 3.コミットする

tx.Commit()

の組み合わせで実行します。

sqlxでSelect文でデータを取得して構造化データに結果を格納する

Select結果をうける構造体を以下のように定義したとして。

type Results struct {
    Id int
    Name string
}

その構造体の配列を作り

rows := []Results{}

 その配列のポインタを渡してSelectを実行すると、結果用の構造体の配列に値をセットしてくれます。

dbx.Select(&rows, "select id,name from gotest where id <= 10")

 とりあえず、これで一通りのことはできます。

前回と同じ処理をsqlxで書き直す

前回(1)の時のサンプルと全く同じ処理を、sqlxの上記を使って書き直します。

前回のリンクはこちらです。

arakan-pgm-ai.hatenablog.com

以下、それをsqlxを使って書き直したものです。

package main

import (
	"fmt"
	"strconv"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

func blog02() {
	// MariaDBを開きます。
	dbx, dberr := sqlx.Open("mysql", "bltuser:bltpass@tcp(localhost:3306)/bltdb")
	if dberr != nil {
		println("データベースオープンに失敗しました")
		panic(dberr)
	}
	defer dbx.Close()
	// タイムアウトは3分に設定
	dbx.SetConnMaxLifetime(time.Minute * 3)
	// 接続数はとりあえず10に設定
	dbx.SetMaxOpenConns(10)
	dbx.SetMaxIdleConns(10)

	tx := dbx.MustBegin()
	var name = "テスト文字列:その"
	for id := 1; id < 10; id++ {
		tx.MustExec("insert into gotest values(?,?)", id, name+strconv.Itoa(id))
	}
	tx.Commit()

	type Results struct {
		Id   int
		Name string
	}

	rows := []Results{}
	dbx.Select(&rows, "select id,name from gotest where id <= 10")
	for i, _ := range rows {
		fmt.Printf("取得したIDは「%d」:NAMEは「%s」です。\n", rows[i].Id, rows[i].Name)
	}

	tx2 := dbx.MustBegin()
	tx2.MustExec("update gotest set name=? where id < 5", "IDが5より小さい")
	tx2.Commit()

	rows2 := []Results{}
	dbx.Select(&rows2, "select id,name from gotest where id <= 10")
	for _, s := range rows2 {
		fmt.Printf("更新後に取得したIDは「%d」:NAMEは「%s」です。\n", s.Id, s.Name)
	}

	tx3 := dbx.MustBegin()
	tx3.MustExec("delete from gotest")
	tx3.Commit()
}

func main() {
	blog02()
}

劇的にすっきりしました。 

Selectの結果を構造体の配列にセットしてくれるので、後処理も普通にrangeを使って配列のループとして回して処理できるのもやりやすいです。

個人的には、我慢して「 database/sql」を使う理由はないです。

SQL文を生成できれば、これで一通り基本的なデータ取得と更新はできそうです。

ではでは。