Go言語でjackc/pgxを使ったPostgreSQLを使う機会ができたので、最小構成でスタートさせて理解を深めようとしました。
動作環境
$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.1 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.1 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
$ go version
go version go1.19.3 linux/amd64
プロジェクトの初期化
go.mod
にはモジュール名とGoのバージョンのみを指定します。
$ mkdir go-postgres-sample
$ cd go-postgres-sample
$ go mod init go-postgres-sample
module go-postgres-sample
go 1.19
PostgreSQLサーバーを立ち上げる(docker-compose)
ここでは docker-compose
を用いてPostgreSQLを立ち上げます。
下記の構成でファイルを用意して、ローカルで実行された postgres.go
からDockerのポートフォワーディングを通してPostgreSQLコンテナーに接続します。
├── docker-compose.yml
├── go.mod
├── go.sum
├── postgres
│ └── 00-initilize-user-table.sql
└── postgres.go
docker-compose.yml
は次の内容にします。接続確認ができる簡単なものです。
version: '3'
services:
postgres:
container_name: go-postgres-sample
image: postgres:15.1-alpine
ports:
- 5432:5432
volumes:
- ./postgres:/docker-entrypoint-initdb.d
environment:
POSTGRES_USER: go-dev
POSTGRES_PASSWORD: go-dev
restart: always
PostgreSQLコンテナーの /docker-entrypoint-initdb.d
に任意のSQLを置くと初回起動時に実行してくれます。
--テーブルを作成
CREATE TABLE users (
id serial primary key,
screen_name text not null,
created timestamp with time zone not null default CURRENT_TIMESTAMP,
updated timestamp with time zone not null default CURRENT_TIMESTAMP
);
--テーブルにデータを挿入
INSERT INTO users("screen_name") VALUES ('go');
準備ができたらPostgreSQLコンテナーを立ち上げます。
$ docker compose up -d
データベースが先ほどのSQLで初期化されているかどうかは docker compose logs
で確認できます。
$ docker compose logs
...
go-postgres-sample | /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/00-initilize-user-table.sql
次の表示が出てデータベースが初期化されない場合は docker-compose.yml
の volumes
が正しいか確認します。
/usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
jackc/pgxでクエリーを実行するサンプル
Goのプログラムは次の通りです。
package main
import (
"context"
"flag"
"fmt"
"os"
"github.com/jackc/pgx/v5"
)
func main() {
// "-uri" コマンドライン引数でPostgresの接続情報を取得
uri := flag.String("uri", "", "Postgres URI")
// flag.Parse()がないと値がデフォルト値になる
flag.Parse()
// コマンドライン引数のチェック
if *uri == "" {
fmt.Println("-uri option is required. \n example: postgres://username:password@localhost:5432/database_name")
os.Exit(1)
}
// コネクションの作成
fmt.Printf("Connecting: %v\n", *uri)
conn, err := pgx.Connect(context.Background(), *uri)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
os.Exit(1)
}
defer conn.Close(context.Background())
// クエリー
var screen_name string
err = conn.QueryRow(context.Background(), "select screen_name from users where id=1").Scan(&screen_name)
if err != nil {
fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
os.Exit(1)
}
fmt.Printf("Hello, @%v!\n", screen_name)
}
パッケージの入手と動作確認
go mod tidy
で postgres.go
にある jackc/pgx
を取得し、 go.mod
を更新します。そのあとに go run
でビルドと実行ができます。
$ go mod tidy
$ go run postgres.go -uri postgres://go-dev:go-dev@127.0.0.1:5432/go-dev
Connecting: postgres://go-dev:go-dev@127.0.0.1:5432/go-dev
Hello, @go!
これで動作確認できました。そのほかに pgxpool
を用いてスレッドセーフなコネクションプールでPostgreSQLを操作することができます。
参考
pgx package - github.com/jackc/pgx/v5 - Go Packages
https://pkg.go.dev/github.com/jackc/pgx/v5
pgxpool package - github.com/jackc/pgx/v5/pgxpool - Go Packages
https://pkg.go.dev/github.com/jackc/pgx/v5/pgxpool
postgres - Official Image | Docker Hub
https://hub.docker.com/_/postgres