lelelemon’s blog

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

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

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

 

以下サンプル。

golangMysql に接続

MySQL を準備

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

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

(前提)

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

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

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

 

[docker-compose.yml]

version: '3'
services:
  # MYSQL
  db:
    image: mysql:8.0.23
    ports:
      - "3306:3306"
    container_name: mysql_host
    environment:
      MYSQL_ROOT_PASSWORD: mysql
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - ./db/data:/var/lib/mysql
      - ./db/my.cnf:/etc/mysql/conf.d/my.cnf
      - ./db/sql:/docker-entrypoint-initdb.d

 

mysql -h 127.0.0.1 --port 3306 -uroot -pmysql

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

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

mysql -h 127.0.0.1 --port 3306 -uroot -pmysql
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.23 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql

 

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

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

 Go-MySQL-Driver ライブラリを使用しました。

 

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

mkdir sample

go mod init sample

touch main.go

 

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

 

package main

import (
    "database/sql"
    "fmt"
    "time"

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

func main() {
    db, err := sql.Open("mysql", "root:mysql@/sample")

    if err != nil {
        panic(err)
    }

    // See "Important settings" section.
    db.SetConnMaxLifetime(time.Minute * 3)
    db.SetMaxOpenConns(10)
    db.SetMaxIdleConns(10)

    fmt.Println("DB接続")
}

 

github.com/go-sql-driver/mysql」のところでコンパイルエラーになるので、

go mod tidy

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

 

MySQLには事前にsampleデータベースを作っておきます。(「CREATE DATABASE IF NOT EXISTS sample;」 を実行)

show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sample             |
| sys                |
+--------------------+
5 rows in set (0.01 sec)

 

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

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

go run main.go 
DB接続

 

MySQLへのCRUD処理を追加

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

 

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

use samle;

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

 
MySQLへデータ登録

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

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

 

package main

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

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

func main() {
    db, err := sql.Open("mysql", "root:mysql@/sample")

    if err != nil {
        panic(err)
    }

    // See "Important settings" section.
    db.SetConnMaxLifetime(time.Minute * 3)
    db.SetMaxOpenConns(10)
    db.SetMaxIdleConns(10)

    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 (?, ?)", 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: 1, 名前: test, 年齢: 10

 

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

select * from user;
+----+------+------+
| id | name | age  |
+----+------+------+
|  1 | test |   10 |
+----+------+------+
1 row in set (0.00 sec)

 

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

 

MySQLへデータ更新

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

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

 

func main() {
    db, err := sql.Open("mysql", "root:mysql@/sample")

    if err != nil {
        panic(err)
    }

    // See "Important settings" section.
    db.SetConnMaxLifetime(time.Minute * 3)
    db.SetMaxOpenConns(10)
    db.SetMaxIdleConns(10)

    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 = ?, age = ? WHERE id = ?", 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

 

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

select * from user where id = 1;
+----+-------------+------+
| id | name        | age  |
+----+-------------+------+
|  1 | test_update |   20 |
+----+-------------+------+
1 row in set (0.00 sec)

 

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

 

MySQLへデータ検索

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

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

 

func main() {
    db, err := sql.Open("mysql", "root:mysql@/sample")

    if err != nil {
        panic(err)
    }

    // See "Important settings" section.
    db.SetConnMaxLifetime(time.Minute * 3)
    db.SetMaxOpenConns(10)
    db.SetMaxIdleConns(10)

    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 = ?", id)

    var selectedID int
    var selectedName string
    var selectedAge int

    // 取得したレコードの値をスキャン
    err := row.Scan(&selectedID, &selectedName, &selectedAge)
    if err != nil {
        log.Fatal(err)
    }

    // 取得したレコードの内容を表示
    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

 

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

select * from user where id = 1;
+----+-------------+------+
| id | name        | age  |
+----+-------------+------+
|  1 | test_update |   20 |
+----+-------------+------+
1 row in set (0.00 sec)

 

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

 

MySQLへデータ削除

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

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

 

func main() {
    db, err := sql.Open("mysql", "root:mysql@/sample")

    if err != nil {
        panic(err)
    }

    // See "Important settings" section.
    db.SetConnMaxLifetime(time.Minute * 3)
    db.SetMaxOpenConns(10)
    db.SetMaxIdleConns(10)

    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 = ?", 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
削除しました。

 

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

mysql> select * from user where id = 1;
Empty set (0.00 sec)

 

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

 

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