lelelemon’s blog

カメの歩みでのんびり学んでいます。

【Go言語】DB接続サンプル(PostgreSQL)

golangでDB接続(PostgreSQL)を試したのでそのサンプルです。

 

以下サンプル。

golangPostgreSQL に接続

PostgreSQL を準備

まずは接続先のPostgreSQL環境を準備します。

ここは手っ取り早く、Docker で環境を作りました。

(前提)

Docker がインストール済みであること

postgresql がインストール済みであること(psql コマンドを使用して DB接続を確認するため)

下記の docker-compose.yml を作成し、「docker-compose up -d」で起動します。

 

[docker-compose.yml]

version: '3'

services:
  postgres:
    image: postgres:14
    container_name: postgres
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: sample
      TZ: "Asia/Tokyo"
      PGDATA: /var/lib/postgresql/data/pgdata
    ports:
      - 5432:5432
    volumes:
      - ./db-store:/var/lib/postgresql/data

 

docker exec -it postgres psql -U user -d sample

上記コマンドでPostgreSQLに接続ができます。

これでPostgreSQL環境構築は完了です。

docker exec -it postgres psql -U user -d sample
psql (14.10 (Debian 14.10-1.pgdg120+1))
Type "help" for help.

sample=# 

 

Goプログラムから PostgreSQLに接続

続いて、Go でPostgreSQL に接続する処理を書いていきます。

pq ライブラリを使用しました。

 

下記で各種ファイルを用意します。

mkdir sample

go mod init sample

touch main.go

 

まずは main.go には下記の内容を記載します。

 

package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/lib/pq"
)

func main() {
    connStr := "user=user password=password dbname=sample sslmode=disable"
    _, err := sql.Open("postgres", connStr)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("DB接続")
}

 

「_ "github.com/lib/pq"」のところでコンパイルエラーになるので、

go mod tidy

を実行することで、pq が go.mod の依存関係に追加されます。(go.mod ファイルが更新される)

 

ここまでできたら、main.go を実行します。

「DB接続」と表示されれば、問題なく接続ができています。

go run main.go 
DB接続

 

PostgreSQLへのCRUD処理を追加

接続するだけだと面白くないので、DBへのCRUDも試します。

 

まずは動作検証用のテーブルを用意。

CREATE TABLE "user" (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255),
    age INT
);

 
PostgreSQLへデータ登録

続いてデータの登録です。

データ登録用の dbInsert 関数を追加しています。

 

package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/lib/pq"
)

func main() {
    connStr := "user=user password=password dbname=sample sslmode=disable"
    db, err := sql.Open("postgres", connStr)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("DB接続")

    // コマンドラインからの入力を受け付ける
    var command string
    fmt.Print("コマンドを入力 (insert/update/delete/select): ")
    fmt.Scan(&command)

    switch command {
    case "insert":
        dbInsert(db)
    default:
        fmt.Println("無効なコマンド")
    }
}

func dbInsert(db *sql.DB) {
    var name string
    var age int

    fmt.Print("名前を入力: ")
    fmt.Scan(&name)

    fmt.Print("年齢を入力: ")
    fmt.Scan(&age)

    // INSERT文を実行
    result, err := db.Exec("INSERT INTO \"user\" (name, age) VALUES ($1, $2)", name, age)
    if err != nil {
        log.Fatal(err)
    }

    // 追加成功時のメッセージと追加されたレコード内容を表示
    fmt.Println("追加しました。")
    lastInsertID, _ := result.LastInsertId()
    fmt.Printf("追加されたレコードのID: %d, 名前: %s, 年齢: %d\n", lastInsertID, name, age)

}

 

コマンドラインから、insert/update/delete/select のいずれかの入力を受け付け、

insert の場合にデータ登録を行うようにしています。

これを実行してみます。

go run main.go 
DB接続
コマンドを入力 (insert/update/delete/select): insert
名前を入力: test
年齢を入力: 10
追加しました。
追加されたレコードのID: 0, 名前: test, 年齢: 10

 

PostgreSQLにもSelect句を投げてみます。

select * from public.user;
 id | name | age 
----+------+-----
  1 | test |  10
(1 row)

 

無事に登録できています。

 

PostgreSQLへデータ更新

続いてデータの更新です。

データ更新用の dbUpdate 関数を追加しています。

 

func main() {
    connStr := "user=user password=password dbname=sample sslmode=disable"
    db, err := sql.Open("postgres", connStr)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("DB接続")

    // コマンドラインからの入力を受け付ける
    var command string
    fmt.Print("コマンドを入力 (insert/update/delete/select): ")
    fmt.Scan(&command)

    switch command {
    case "insert":
        dbInsert(db)
    case "update":
        dbUpdate(db)
    default:
        fmt.Println("無効なコマンド")
    }
}

func dbUpdate(db *sql.DB) {
    var id int
    var name string
    var age int

    fmt.Print("更新対象のレコードのIDを入力: ")
    fmt.Scan(&id)

    fmt.Print("名前を入力: ")
    fmt.Scan(&name)

    fmt.Print("年齢を入力: ")
    fmt.Scan(&age)

    // UPDATE文を実行
    result, err := db.Exec("UPDATE \"user\" SET name = $1, age = $2 WHERE id = $3", name, age, id)
    if err != nil {
        log.Fatal(err)
    }

    // 更新成功時のメッセージと更新されたレコード内容を表示
    rowsAffected, _ := result.RowsAffected()
    if rowsAffected > 0 {
        fmt.Println("更新しました。")
        fmt.Printf("更新されたレコードのID: %d, 新しい名前: %s, 新しい年齢: %d\n", id, name, age)
    } else {
        fmt.Println("指定されたIDのレコードが見つかりませんでした。")
    }
}

 

コマンドラインからの入力が、update の場合にデータ更新を行うようにしています。

これを実行してみます。

go run main.go 
DB接続
コマンドを入力 (insert/update/delete/select): update
更新対象のレコードのIDを入力: 1
名前を入力: test_update
年齢を入力: 20
更新しました。
更新されたレコードのID: 1, 新しい名前: test_update, 新しい年齢: 20

 

PostgreSQLにもSelect句を投げてみます。

select * from public.user where id = 1;
 id |    name     | age 
----+-------------+-----
  1 | test_update |  20
(1 row)

 

無事に更新できています。

 

PostgreSQLへデータ検索

続いてデータの検索です。

データ検索用の dbSelect 関数を追加しています。

 

func main() {
    connStr := "user=user password=password dbname=sample sslmode=disable"
    db, err := sql.Open("postgres", connStr)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("DB接続")

    // コマンドラインからの入力を受け付ける
    var command string
    fmt.Print("コマンドを入力 (insert/update/delete/select): ")
    fmt.Scan(&command)

    switch command {
    case "insert":
        dbInsert(db)
    case "update":
        dbUpdate(db)
    case "select":
        dbSelect(db)
    default:
        fmt.Println("無効なコマンド")
    }
}
 
func dbSelect(db *sql.DB) {
    var id int

    fmt.Print("検索対象のレコードのIDを入力: ")
    fmt.Scan(&id)

    // SELECT文を実行
    row := db.QueryRow("SELECT id, name, age FROM \"user\" WHERE id = $1", id)

    var selectedID int
    var selectedName string
    var selectedAge int

    // 取得したレコードの値をスキャン
    err := row.Scan(&selectedID, &selectedName, &selectedAge)
    if err != nil {
        if err == sql.ErrNoRows {
            fmt.Println("指定されたIDのレコードが見つかりませんでした。")
        } else {
            log.Fatal(err)
        }
        return
    }

    // 取得したレコードの内容を表示
    fmt.Printf("ID: %d, 名前: %s, 年齢: %d\n", selectedID, selectedName, selectedAge)
}

 

コマンドラインからの入力が、select の場合にデータ検索を行うようにしています。

これを実行してみます。

go run main.go 
DB接続
コマンドを入力 (insert/update/delete/select): select
検索対象のレコードのIDを入力: 1
ID: 1, 名前: test_update, 年齢: 20

 

PostgreSQLにもSelect句を投げてみます。

select * from public.user where id = 1;
 id |    name     | age 
----+-------------+-----
  1 | test_update |  20
(1 row)

 

無事に検索できています。

 

PostgreSQLへデータ削除

続いてデータの削除です。

データ削除用の dbDelete 関数を追加しています。

 

func main() {
    connStr := "user=user password=password dbname=sample sslmode=disable"
    db, err := sql.Open("postgres", connStr)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("DB接続")

    // コマンドラインからの入力を受け付ける
    var command string
    fmt.Print("コマンドを入力 (insert/update/delete/select): ")
    fmt.Scan(&command)

    switch command {
    case "insert":
        dbInsert(db)
    case "update":
        dbUpdate(db)
    case "select":
        dbSelect(db)
    case "delete":
        dbDelete(db)
    default:
        fmt.Println("無効なコマンド")
    }
}
 
func dbDelete(db *sql.DB) {
    var id int

    fmt.Print("削除対象のレコードのIDを入力: ")
    fmt.Scan(&id)

    // DELETE文を実行
    result, err := db.Exec("DELETE FROM \"user\" WHERE id = $1", id)
    if err != nil {
        log.Fatal(err)
    }

    // 削除成功時のメッセージを表示
    rowsAffected, _ := result.RowsAffected()
    if rowsAffected > 0 {
        fmt.Println("削除しました。")
    } else {
        fmt.Println("指定されたIDのレコードが見つかりませんでした。")
    }
}

 

コマンドラインからの入力が、delete の場合にデータ削除を行うようにしています。

これを実行してみます。

go run main.go 
DB接続
コマンドを入力 (insert/update/delete/select): delete
削除対象のレコードのIDを入力: 1
削除しました。

 

PostgreSQLにもSelect句を投げてみます。

select * from public.user where id = 1;
 id | name | age 
----+------+-----
(0 rows)

 

無事に削除できています。

 

以上サンプルになります。