作成:2023年7月12日
PosgreSQLの練習で、DockerでPostgreSQLを立てて、Go言語でアクセスしてみました。
docker-compose.ymlを作成
# docker-composeで使用するバージョンを定義しています。2022年5月時点では、3.9が最新です。
version: '3.9'
# サービス (コンテナ) を定義します。
services:
# 今回は postgres をサービスとして定義しました。
postgres:
# Docker Image は postgres:12-alpine を使います。postgres:12-alpine は postgres:12 と比較して、イメージサイズが小さくなっています。
image: postgres:12-alpine
# コンテナの名前を指定します。
container_name: postgres
# 環境変数を設定します。
environment:
- POSTGRES_USER=root
- POSTGRES_PASSWORD=root
- POSTGRES_DB=testdb
# データの永続化
volumes:
# postgresボリュームを/var/lib/postgresql/dataにマウントします
- postgres:/var/lib/postgresql/data
# ポートの指定(HOST:CONTAINER)
ports:
- 5432:5432
# データの永続化:ボリュームを作成します。
volumes:
postgres:
コンテナ立ち上げ
コンテナを立ち上げて、PosgreSQLを確認します。
$ docker-compose up -d
% docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
835d849809e8 postgres:12-alpine "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp postgres
% docker exec -it postgres bash
835d849809e8:/# psql -l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+-------+----------+------------+------------+-------------------
postgres | root | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | root | UTF8 | en_US.utf8 | en_US.utf8 | =c/root +
| | | | | root=CTc/root
template1 | root | UTF8 | en_US.utf8 | en_US.utf8 | =c/root +
| | | | | root=CTc/root
testdb | root | UTF8 | en_US.utf8 | en_US.utf8 |
(4 rows)
835d849809e8:/#
PostgreSQLに接続してテーブル作成
PostgreSQLに接続します。
835d849809e8:/# psql -h localhost -p 5432 -U root -d testdb
psql (12.15)
Type "help" for help.
testdb=#
テーブルを作成します。
testdb=# create table members (
testdb(# id serial primary key,
testdb(# first_name varchar(255),
testdb(# last_name varchar(255),
testdb(# email varchar(255),
testdb(# accessprev boolean
testdb(# );
CREATE TABLE
testdb=# INSERT INTO members VALUES (1, 'ichiro', 'tanaka', 'ichiro@gmail.com', TRUE);
INSERT 0 1
testdb=# INSERT INTO members VALUES (2, 'jiro', 'sato', 'jiro@gmail.com', FALSE);
INSERT 0 1
testdb=# INSERT INTO members VALUES (3, 'hanako', 'suzuki', 'hanako@gmail.com', TRUE);
INSERT 0 1
testdb=# SELECT * FROM members;
id | first_name | last_name | email | accessprev
----+------------+-----------+------------------+------------
1 | ichiro | tanaka | ichiro@gmail.com | t
2 | jiro | sato | jiro@gmail.com | f
3 | hanako | suzuki | hanako@gmail.com | t
(3 rows)
testdb=#
Goのコード準備
package main
import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
)
var Db *sql.DB
func init() {
var err error
// DB名やユーザー、テーブルは適宜適切な値を入れてください
Db, err = sql.Open("postgres", "user=root dbname=testdb password=root sslmode=disable")
if err != nil {
panic(err)
}
}
type Member struct {
Id int
FirstName string
LastName string
Email string
AccessPrev bool
}
func main() {
fmt.Println("----- Query 1 -----")
rows, err := Db.Query("SELECT * FROM members ORDER BY id")
if err != nil {
return
}
for rows.Next() {
m := Member{}
rows.Scan(&m.Id, &m.FirstName, &m.LastName, &m.Email, &m.AccessPrev)
fmt.Println(m)
}
fmt.Println()
fmt.Println("----- Query 2 -----")
rows, err = Db.Query("SELECT * FROM members WHERE accessprev = $1 ORDER BY id", "false")
if err != nil {
return
}
for rows.Next() {
m := Member{}
rows.Scan(&m.Id, &m.FirstName, &m.LastName, &m.Email, &m.AccessPrev)
fmt.Println(m)
}
fmt.Println()
fmt.Println("----- QueryRow -----")
m := Member{}
err = Db.QueryRow("SELECT * FROM members WHERE accessprev = $1 ORDER BY id", "true").Scan(&m.Id, &m.FirstName, &m.LastName, &m.Email, &m.AccessPrev)
if err != nil {
return
}
fmt.Println(m)
fmt.Println()
fmt.Println("----- Prepare -----")
statement := "SELECT * FROM members WHERE accessprev = $1 ORDER BY id"
stmt, err := Db.Prepare(statement)
if err != nil {
return
}
defer stmt.Close()
rows, err = stmt.Query("false")
for rows.Next() {
m := Member{}
rows.Scan(&m.Id, &m.FirstName, &m.LastName, &m.Email, &m.AccessPrev)
fmt.Println(m)
}
fmt.Println()
fmt.Println("----- Exec -----")
_, err = Db.Exec("INSERT INTO members VALUES ($1, $2, $3, $4, $5)", 4, "takashi", "yamamoto", "yamamoto@yahoo.co.jp", "FALSE")
if err != nil {
return
}
rows, err = Db.Query("SELECT * FROM members ORDER BY id")
if err != nil {
return
}
for rows.Next() {
m := Member{}
rows.Scan(&m.Id, &m.FirstName, &m.LastName, &m.Email, &m.AccessPrev)
fmt.Println(m)
}
fmt.Println()
}
・DB.Query:単純にクエリを実行したいときに使えます。func (*DB) Query
・Query()はRows型を返します。SQLの結果が複数行を想定しています。type Rows
Rows型のメソッドの Next() で行があるか判断して、Scan() で値を取得しています。
・Query()関数はプレイスホルダーも使えます。SQL文に $1 などの書き方で引数で実際の値を設定できます。
rows, err = Db.Query("SELECT * FROM members WHERE accessprev = $1 ORDER BY id", "false")
この例では第1引数の false が $1 に入ります。
・QueryRow() は Rows型を返します。一行のSQL結果が返るのを想定してScan()を使っています。func (*DB) RueryRow
・Prepare() は SQL文だけで stmtオブジェクトを作り、クエリを実行するメソッドと分けることができます。func (*DB) Prepare
・Exec() は単純にクエリを実行して、結果の行を返さないメソッドです。大抵はdelete、insertで使うそうです。func (*DB) Exec
Goの postgresドライバーをインストール
go init してから、 go get します。
% go mod init test-postgres
go: creating new go.mod: module test-postgres
go: to add module requirements and sums:
go mod tidy
% go get github.com/lib/pq
go: added github.com/lib/pq v1.10.9
実行
Docker上の PostgrSQL に、 Goプログラムからアクセスできました。
% ls
docker-compose.yml go.mod go.sum main.go
% go run main.go
----- Query 1 -----
{1 ichiro tanaka ichiro@gmail.com true}
{2 jiro sato jiro@gmail.com false}
{3 hanako suzuki hanako@gmail.com true}
----- Query 2 -----
{2 jiro sato jiro@gmail.com false}
----- QueryRow -----
{1 ichiro tanaka ichiro@gmail.com true}
----- Prepare -----
{2 jiro sato jiro@gmail.com false}
----- Exec -----
{1 ichiro tanaka ichiro@gmail.com true}
{2 jiro sato jiro@gmail.com false}
{3 hanako suzuki hanako@gmail.com true}
{4 takashi yamamoto yamamoto@yahoo.co.jp false}
% docker-compose down
[+] Running 2/2
✔ Container postgres Removed 0.2s
✔ Network sql20230711_default Removed 0.1s
以上、お試しでやってみました。
参考
・Docker で PostgreSQL 上にデータベースを作成しよう
・Go言語でSQLを実行してみる
・PostgreSQLへの接続と切断
・データを取得する(SELECT文)
・初心者の僕がGO言語でpostgresSQLをいじるまで。
・https://github.com/lib/pq
・データ接続のパッケージをインポート
・$ go mod init mysql-example
・init関数のふしぎ #golang