0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GORMでMYSQLに接続してCRUD操作する

Posted at

#はじめに
転職にあたりgo言語を使用することになったので勉強して2日くらいです。
書き方なんとなくだけど分かったので、文字読むより手を動かそうと思い、いきなりDB接続しようとしたらめちゃ時間かかった(当たり前)のでその備忘録です。
間違いや、よろしくない書き方などあったらぜひぜひコメントで教えていただけると嬉しいです。
とにかくDBつないで動かしてみることが目的なので実用的ではないかもしれません。

#環境
GOやMYSQLの環境構築は割愛。調べればたくさん出てきます。

OS: windows
go version: go1.17.1 windows/amd64
mysql version: Ver 8.0.26 for Win64 on x86_64 (MySQL Community Server - GPL)

#GORMとは
GO言語のORMライブラリです。公式がとても分かりやすい

##ORMとは
Object-relational mappingの略です。
名前の通り、オブジェクト(オブジェクト指向におけるオブジェクト)と関係(RDB)とのマッピングを行うものです。
超簡単に言うと、SQLを直接書かなくていいやつ。
詳しく知りたい方は調べてみてください。

#インストール

.sh
#gorm
$ go get -u github.com/jinzhu/gorm

# mysql
$ go get -u github.com/go-sql-driver/mysql

#MYSQLに接続
ひとまずCRUDは置いておいて接続を先にしてみます。
以下のように記述しました。go runで走らせてエラーが出なければ接続ができているはずです。

main.go
package main

import (
	"fmt"
	"log"
	"time"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

const (
	DBMS = "mysql"
	DB_USER = "ユーザー名"
	DB_PASS = "パスワード"
	DB_PROTOCOL = "tcp(127.0.0.1:3306)"
	DB_NAME = "DB名"
)

func connectGorm() *gorm.DB {
	connectTemplate := "%s:%s@%s/%s?parseTime=True"
	connect := fmt.Sprintf(connectTemplate, DB_USER, DB_PASS, DB_PROTOCOL, DB_NAME)
	db, err := gorm.Open(DBMS, connect)

	if err != nil {
		log.Println(err.Error())
	}

	return db
}

func main() {
	db := connectGorm()
	defer db.Close()
}

##connectGorm()について捕捉
接続の設定は以下のように書きます

main.go

    db, err := gorm.Open("mysql", "ユーザー名:パスワード@/DB名")

    if err != nil {
        panic(err.Error())
    }
    return db

ユーザー名等は一括管理したいなと思い、constで定義してフォーマットさせました。ymlファイル的なの作りたいけどディレクトリ構造とかわからないのでそれはおいおい。。。

MySQLだと文字コードの問題で?parseTime=trueを末尾につける必要があるらしいのでつけました。

#テーブル定義
テーブルを定義してマイグレーションしたら作ってくれるらしい。
構造体でテーブルの構造を定義します。たぶんentity的な感じ。プロジェクト情報を持つテーブルを作ってみます。

以下を追加

main.go
type Projects struct {
	gorm.Model
	Name    string `gorm:"size:50"`
	Detail  string `gorm:"size:255"`
}

func main() {
 
	db.Set("gorm:table_options", "ENGINE = noDB").AutoMigrate(&Projects{})

カラム名にあたる部分はパスカルケースで書かないと認識してくれなかったので注意が必要です。DBではスネークケースで登録されます。(例:UserId → user_id)

db.Set("gorm:table_options", "ENGINE = noDB").AutoMigrate(&Projects{})でテーブルが存在しない時に対象のテーブルを作成してくれます。

実行後にDBを確認するとテーブルが作られています。

.sh
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int unsigned | NO   | PRI | NULL    | auto_increment |
| created_at | datetime     | YES  |     | NULL    |                |
| updated_at | datetime     | YES  |     | NULL    |                |
| deleted_at | datetime     | YES  | MUL | NULL    |                |
| name       | varchar(50)  | YES  |     | NULL    |                |
| detail     | varchar(255) | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)

以下のカラムは自動で追加されました。
id
created_at
updated_at
deleted_at

これはgorm.Modelを使用したためです。Modelの中身を見てみると自動追加されている4つの項目が書かれていました。

model.go
package gorm

import "time"

// Model base model definition, including fields `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`, which could be embedded in your models
//    type User struct {
//      gorm.Model
//    }
type Model struct {
	ID        uint `gorm:"primary_key"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt *time.Time `sql:"index"`
}

#CRUD操作
テーブルができたのでCRUDの操作をしてみましょう。

##CREATE

insertの関数を追加します。

main.go
func insert(projects []Projects, db *gorm.DB) {
	for _, project := range projects {
		db.Create(&project)
	}
}

実際にinsertするときは以下のように使用します。

main.go
	project := Projects{Name: "プロジェクト名", Detail: "詳細"}
	insertProjects := []Projects{project}
	insert(insertProjects, db)

##READ
###全件取得

main.go
func findAll(db *gorm.DB) []Projects {
	var allProjects []Projects
	db.Find(&allProjects)
	return allProjects
}

###指定したIDのデータを取得

main.go
func findByID(db *gorm.DB, id int) Projects {
	var project Projects
	db.First(&project, id)
	return project
}

引数でIDを渡して検索しています。
存在しない場合は初期値が返ってきます。

###指定した名前のデータを取得

main.go
func findByName(db *gorm.DB, name string) []Projects {
	var project []Projects
	db.Where("name = ?", name).Find(&project)
	return project
}

IDと同じような書き方です。wherefindを合わせて使っています。
ヒットしたものをすべて返します。

##UPDATE
###IDをキーに更新

main.go
func updateWhereID(id int, newName string, db *gorm.DB) {
	var project Projects
	db.Model(&project).Where("id = ?", id).Update("name", newName)
}

##DELETE

###IDをキーに削除

main.go
func deleteByID(id int, db *gorm.DB) {
	var project Projects
	db.Where("id = ?", id).Delete(project)
}

####捕捉
gorm.Modelを使用していてdeleted_atカラムが存在する場合は、deleted_atに時間が追加されて取得されなくなります。つまり**倫理削除(UPDATE)**されます。

deleted_atカラムがない場合は物理削除されます。

#参考サイト
https://gorm.io/ja_JP/docs/create.html
gormを使ってローカル環境のMySQLとCRUD操作
Gormを触ってみた(MySQL)

#さいごに
2日目にしてはまあできたほうなんじゃないでしょうか。
とにかく動くことだけを目的に作ったのでもっとMVCライクな感じに書きたいです。いい記事がなかなか見つからず、古い記事を参考に、公式を見ながら直しつつ書いたのであまりにひどかったらコメントください。。
次回は整理してファイル分けしたり、GIN使ってJSONで返すようにしたりしてみたいです。

さいごまで読んでいただきありがとうございます!

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?