LoginSignup
0
0

More than 1 year has passed since last update.

GORMを使用してMySQLに接続し、データベースの作成・削除とCRUD機能を実装する

Posted at

概要

GORMを初めて使用したので、基本的な使用方法をアウトプットのため投稿する。

■ Go version
go1.15.7
■ MySQL version
5.7.37

GORMを導入する

以下のコードで必要なパッケージをインストールすることができる。

go mod init [任意の値]
go get -u gorm.io/gorm
go get -u github.com/go-sql-driver/mysql

テーブルの作成

以下のコードでテーブルの作成・削除が可能であった。

GOのコード

migrate.go
package main

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type Data1 struct {
    gorm.Model
	Title    string
	Content  string
}

func main() {
    dsn := "[ユーザー名]:[パスワード]@tcp(127.0.0.1:3306)/[スキーマ―名]?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
		panic("failed to connect database")
	} else {
        up01(dsn, db)
        down01(dsn, db);
	}
}

func up01(dsn string, db *gorm.DB) {
    db.AutoMigrate(Data1{})
}
func down01(dsn string, db *gorm.DB) {
    db.Migrator().DropTable(Data1{})
}

作成されるテーブル

CREATE TABLE `data1` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    `created_at` datetime(3) DEFAULT NULL,
    `updated_at` datetime(3) DEFAULT NULL,
    `deleted_at` datetime(3) DEFAULT NULL,
    `title` longtext,
    `content` longtext,
    PRIMARY KEY (`id`),
    KEY `idx_data1_deleted_at` (`deleted_at`)
) ENGINE = InnoDB DEFAULT CHARSET = latin1

解説

1つ1つのコードの解説を記載する。

パッケージ

gorm.io/driver/mysql
gorm.io/gorm

GORMでMySQLを使用するパッケージを導入している。
以下にGItHubのリンクを記載している。
https://github.com/go-gorm/mysql

構造体

type Data1 struct {
    gorm.Model
	Title    string
	Content  string
}

テーブルの生成・削除に使用する構造体を宣言している。
gorm.Modelの記述があることでID, CreatedAt, UpdatedAt, DeletedAtカラムが構造体に記載せずともテーブルに反映されるようになる。
また、構造体名が小文字だと初期化時にフィールドには存在しているが、DB作成時にカラムが生成されていないので大文字にする必要がある。

データベースに接続

dsn := "[ユーザー名]:[パスワード]@tcp(127.0.0.1:3306)/[スキーマ―名]?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})

こちらのページに詳細が記載されているが、上記コードでデータベースに接続可能であった。
ユーザー名、IPアドレス、ポート番号、charset等は各自の環境に合わせて変更する必要がある。

関数呼び出し

if err != nil {
	panic("failed to connect database")
} else {
	up01(dsn, db)
	down01(dsn, db);
}

データベースに接続できた場合に関数を呼び出している。
現状だと2つの関数が実行されるので、テーブルを作成したい場合はdown01関数の呼び出しをコメントアウトし、テーブルを削除したい場合はup01関数の呼び出しをコメントアウトする。

テーブルの作成・削除を行う関数

func up01(dsn string, db *gorm.DB) {
    db.AutoMigrate(Data1{})
}
func down01(dsn string, db *gorm.DB) {
    db.Migrator().DropTable(Data1{})
}

上記内容でテーブルの作成・削除が可能である。

CRUD

以下のコードでCRUD機能を実装した。
解説を記載していく。

package main

import (
	"fmt"
    "gorm.io/gorm"
    "gorm.io/driver/mysql"
)
// 構造体名を大文字にしないと以下のエラーになる
// 「struct field title has json tag but is not exportedstructtag」
type Data1 struct {
    gorm.Model
	Title    string `json:"title"`
	Content  string `json:"content"`
}

func main() {
    dsn := "[ユーザー名]:[パスワード]@tcp(127.0.0.1:3306)/[スキーマ―名]?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
		panic("failed to connect database")
	}

    var data1 Data1
    var data1_arr []Data1

    // Create
    db.Debug().Create(&Data1{Title: "title1", Content: "content1"})

    // Create Multi
    var multi_create = []Data1{{Title: "title2", Content: "content2"}, {Title: "title3", Content: "content3"}, {Title: "title4", Content: "content3"}}
    db.Debug().Create(&multi_create)

    // Read
    db.Debug().First(&data1, 1)
    fmt.Println(data1)
    read_json, err := json.Marshal(data1)
    fmt.Println(string(read_json))

    // Read Multi
    db.Debug().Find(&data1_arr)
    fmt.Println(data1_arr)
    read_multi_json, err := json.Marshal(data1_arr)
    fmt.Println(string(read_multi_json))

    // Update
    db.Debug().Model(&Data1{}).Where("id = ?", 1).Update("Title", "titleUpdate")
    // Update Multi
    db.Debug().Model(&data1).Where("id = ?", 1).Updates(Data1{Title: "titleMultUpdate", Content: "ContentMultUpdate"})

    // Delete
    db.Debug().Delete(&data1, 1)
}

DebugメソッドはターミナルにSQL文を出力するために使用している。

Create

Createメソッドを使用する。
宣言した構造体をポインタを用いて初期化して、挿入したい値を記載する。
&を使用せずに実行すると以下のエラーになる。

panic: reflect: reflect.Value.Set using unaddressable value

1レコードの挿入

db.Create(&Data1{Title: "title1", Content: "content1"})

発行されるSQL

INSERT INTO `data1` (`created_at`,`updated_at`,`deleted_at`,`title`,`content`) VALUES ('2022-08-06 12:52:12.414','2022-08-06 12:52:12.414',NULL,'title1','content1')

複数レコードの挿入

構造体初期化時に配列を使用することで複数レコードの挿入が可能。

var multi_create = []Data1{{Title: "title2", Content: "content2"}, {Title: "title3", Content: "content3"}, {Title: "title4", Content: "content3"}}
db.Debug().Create(&multi_create)
INSERT INTO `data1` (`created_at`,`updated_at`,`deleted_at`,`title`,`content`) VALUES ('2022-08-06 12:52:12.417','2022-08-06 12:52:12.417',NULL,'title2','content2'),('2022-08-06 12:52:12.417','2022-08-06 12:52:12.417',NULL,'title3','content3'),('2022-08-06 12:52:12.417','2022-08-06 12:52:12.417',NULL,'title4','content3')

その後のデーターベース

データーベースを確認すると意図した内容で登録されていることが確認できる。
スクリーンショット 2022-08-06 12.58.17.png

Read

WHERE句の使用

db.Debug().First(&data1, 1)
SELECT * FROM `data1` WHERE `data1`.`id` = 1 AND `data1`.`deleted_at` IS NULL ORDER BY `data1`.`id` LIMIT 1

取得できた値

{{1 2022-08-06 12:52:12.414 +0900 JST 2022-08-06 12:52:12.414 +0900 JST {0001-01-01 00:00:00 +0000 UTC false}} title1 content1}
// JSON変換時
{"ID":1,"CreatedAt":"2022-08-06T12:52:12.414+09:00","UpdatedAt":"2022-08-06T12:52:12.414+09:00","DeletedAt":null,"title":"title1","content":"content1"}

全レコードの取得

Findメソッド内の関数が配列でないと1レコードしか値を取得できないため、配列を使用して初期化しているdata1_arr変数(構造体)を使用している。

db.Debug().Find(&data1_arr)
SELECT * FROM `data1` WHERE `data1`.`deleted_at` IS NULL
[{{1 2022-08-06 12:52:12.414 +0900 JST 2022-08-06 12:52:12.414 +0900 JST {0001-01-01 00:00:00 +0000 UTC false}} title1 content1} {{2 2022-08-06 12:52:12.417 +0900 JST 2022-08-06 12:52:12.417 +0900 JST {0001-01-01 00:00:00 +0000 UTC false}} title2 content2} {{3 2022-08-06 12:52:12.417 +0900 JST 2022-08-06 12:52:12.417 +0900 JST {0001-01-01 00:00:00 +0000 UTC false}} title3 content3} {{4 2022-08-06 12:52:12.417 +0900 JST 2022-08-06 12:52:12.417 +0900 JST {0001-01-01 00:00:00 +0000 UTC false}} title4 content3}]
// JSON変換時
[{"ID":1,"CreatedAt":"2022-08-06T12:52:12.414+09:00","UpdatedAt":"2022-08-06T12:52:12.414+09:00","DeletedAt":null,"title":"title1","content":"content1"},{"ID":2,"CreatedAt":"2022-08-06T12:52:12.417+09:00","UpdatedAt":"2022-08-06T12:52:12.417+09:00","DeletedAt":null,"title":"title2","content":"content2"},{"ID":3,"CreatedAt":"2022-08-06T12:52:12.417+09:00","UpdatedAt":"2022-08-06T12:52:12.417+09:00","DeletedAt":null,"title":"title3","content":"content3"},{"ID":4,"CreatedAt":"2022-08-06T12:52:12.417+09:00","UpdatedAt":"2022-08-06T12:52:12.417+09:00","DeletedAt":null,"title":"title4","content":"content3"}]

Update

単一カラム

db.Model(&Data1{}).Where("id = ?", 1).Update("Title", "titleUpdate")
UPDATE `data1` SET `title`='titleUpdate',`updated_at`='2022-08-06 14:48:57.211' WHERE id = 1 AND `data1`.`deleted_at` IS NULL

複数カラム

db.Model(&data1).Where("id = ?", 1).Updates(Data1{Title: "titleMultUpdate", Content: "ContentMultUpdate"})
UPDATE `data1` SET `updated_at`='2022-08-06 14:48:57.217',`title`='titleMultUpdate',`content`='ContentMultUpdate' WHERE id = 2 AND `data1`.`deleted_at` IS NULL

変更後

ID12のレコードのカラムが変更されていることがわかる。
スクリーンショット 2022-08-06 14.57.03.png

エラー

GORMのリファレンスに記載されているが、全レコードの更新を行おうとするとエラーが出る。
Update文ではWHERE句を使用するべきである。

db.Model(&data1).Update("title1", "titleUpdate")

// error
WHERE conditions required

Delete

今回は論理削除を取り扱う。
ID1番のレコードを削除する。

db.Debug().Delete(&data1, 1)
UPDATE `data1` SET `deleted_at`='2022-08-06 14:59:27.779' WHERE `data1`.`id` = 1 AND `data1`.`deleted_at` IS NULL

poiter

ポインタがないとエラーになる

panic: reflect: reflect.Value.Set using unaddressable value

結果

ID1のレコードのdeleted_atカラムに値が挿入されていることが分かる。

スクリーンショット 2022-08-06 15.00.12.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0