🤖
sqlc と pgxpool でトランザクション
モチベーション
sqlc でトランザクションを利用するのは ドキュメント に書いてあるが、 pgxpool を利用したトランザクションのサンプルを整理しておきたい。
まとめ
sqlc と pgx の pgxpool でトランザクションを利用するのは pgxpool.Begin を利用するだけ。
サンプルコード
- サンプルコードのコンパイルは通らない
- サンプルコード自体に意味は特にない
sqlc.yaml
version: "2"
sql:
- queries: "db/query/"
schema: "db/schema/"
engine: "postgresql"
gen:
go:
package: "sqlc"
out: "./gen/sqlc"
sql_package: "pgx/v4"
emit_json_tags: true
emit_prepared_queries: false
emit_interface: true
emit_exact_table_names: false
emit_empty_slices: true
emit_pointers_for_null_types: true
プールを作成する
// pgxpool でコネクションプールを生成する
// connStr は postgres://jack:secret@pg.example.com:5432/mydb?sslmode=verify-ca&pool_max_conns=10 みたいなやつ
func NewPool(connStr string) (*pgxpool.Pool, error) {
// https://pkg.go.dev/github.com/jackc/pgx/v4/pgxpool#ParseConfig
config, err := pgxpool.ParseConfig(connStr)
if err != nil {
return nil, err
}
// https://pkg.go.dev/github.com/jackc/pgx/v4/pgxpool#ConnectConfig
pool, err := pgxpool.ConnectConfig(context.Background(), config)
if err != nil {
return nil, err
}
// https://pkg.go.dev/github.com/jackc/pgx/v4/pgxpool#Pool.Ping
if err := pool.Ping(context.Background()); err != nil {
return nil, err
}
return pool, nil
}
生成したプールを使って sqlc で生成したコードを呼び出す query を作る。
また、トランザクションを利用するように pool も取っておく。
import (
// sqlc generate で生成したコード置き場
db "example.com/gen/sqlc"
)
// 適当にグローバルに置いてるが別にグローバルでなくてもいい
const (
// プール自体もトランザクション用に取っておく
pool = pool,
// sqlc と pgxpool を関連付ける
query = db.New(pool)
)
トランザクションを利用する
func txQuerySample(c context.Context, id string) error {
// pgxpool の Begin を利用する
// https://pkg.go.dev/github.com/jackc/pgx/v4/pgxpool#Pool.Begin
tx, err := pool.Begin(c)
if err != nil {
return err
}
// https://pkg.go.dev/github.com/jackc/pgx/v4/pgxpool#Tx.Rollback
defer tx.Rollback(c)
txQuery := query.WithTx(tx)
spam, err := txQuery.CreateSpam(c, id)
if err != nil {
return err
}
if err := txQuery.UpdateHam(c, spam.Pk); err != nil {
return err
}
if err := txQuery.DeleteSpam(c, spam.Pk); err != nil {
return err
}
// https://pkg.go.dev/github.com/jackc/pgx/v4/pgxpool#Tx.Commit
if err := tx.Commit(c); err != nil {
return err
}
return nil
}
トランザクションを利用しない
func querySample(c context.Context, id string) error {
spam, err := query.CreateSpam(c, id)
if err != nil {
return err
}
if err := query.UpdateHam(c, spam.Pk); err != nil {
return err
}
if err := query.DeleteSpam(c, spam.Pk); err != nil {
return err
}
return nil
}
Discussion