💨
Gorm(golang用ORマッパー)を使う
【環境】
MacBook Air (M1, 2020)
OS: MacOS Big Sur version11.6
Docker Desktop for Mac version4.5.0
MySQLとgolangのsql/databaseでCRUDを実装し、htmlで操作する記事を書きました。
ORマッパー:O(オブジェクト指向)とR(リレーショナルデータベース)の間でデータ形式の相互変換を行う。
database.go
database.go
package utility
import (
"fmt"
"os"
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var Db *gorm.DB
func init() {
user := os.Getenv("MYSQL_USER")
pw := os.Getenv("MYSQL_PASSWORD")
db_name := os.Getenv("MYSQL_DATABASE")
var path string = fmt.Sprintf("%s:%s@tcp(db:3306)/%s?charset=utf8&parseTime=true", user, pw, db_name)
dialector := mysql.Open(path)
var err error
if Db, err = gorm.Open(dialector); err != nil {
connect(dialector, 100)
}
fmt.Println("db connected!!")
}
func connect(dialector gorm.Dialector, count uint) {
var err error
if Db, err = gorm.Open(dialector); err != nil {
if count > 1 {
time.Sleep(time.Second * 2)
count--
fmt.Printf("retry... count:%v\n", count)
connect(dialector, count)
return
}
panic(err.Error())
}
}
- Gormは2020年からバージョン2が利用可能です。
"gorm.io/gorm"
でパッケージをインポートします。
Gormで使うMySQL用のドライバーは
"gorm.io/driver/mysql"
でインポートできます。
標準パッケージのsql/databaseではブランクインポート(パッケージの前に"_ "を記述し、init関数のみを実行)でしたが、Gormで使うドライバーは通常のインポートとなります。 - GormのOpen関数でDBを取得する時、Dialectorを渡します。
DialectorはドライバのOpen関数にMySQL接続情報を渡すことで取得できます。 - MySQLが立ち上がるまで接続を繰り返す際、sql/databaseではPingを繰り返し実行していましたが、GormではOpen関数を実行した時点で接続を試みます。
article.go
article.go
package article
import (
"go_blog/internal/utility"
"html/template"
"log"
"net/http"
"strings"
)
type Article struct {
Id int
Title string
Body string
}
var tmpl *template.Template
func init() {
funcMap := template.FuncMap{
"nl2br": func(text string) template.HTML {
return template.HTML(strings.Replace(template.HTMLEscapeString(text), "\n", "<br />", -1))
},
}
tmpl, _ = template.New("article").Funcs(funcMap).ParseGlob("web/template/*")
utility.Db.Set("gorm:table_options", "ENGINE = InnoDB").AutoMigrate(Article{})
}
func Index(w http.ResponseWriter, r *http.Request) {
var allArticles []Article
utility.Db.Find(&allArticles)
if err := tmpl.ExecuteTemplate(w, "index.html", allArticles); err != nil {
log.Fatal(err)
}
}
func Show(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
var article Article
utility.Db.First(&article, id)
tmpl.ExecuteTemplate(w, "show.html", article)
}
func Create(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
tmpl.ExecuteTemplate(w, "create.html", nil)
} else if r.Method == "POST" {
title := r.FormValue("title")
body := r.FormValue("body")
article := Article{Title: title, Body: body}
utility.Db.Create(&article)
http.Redirect(w, r, "/", 301)
}
}
func Edit(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
id := r.URL.Query().Get("id")
var article Article
utility.Db.First(&article, id)
tmpl.ExecuteTemplate(w, "edit.html", article)
} else if r.Method == "POST" {
title := r.FormValue("title")
body := r.FormValue("body")
id := r.FormValue("id")
var article Article
utility.Db.First(&article, id)
article.Title = title
article.Body = body
utility.Db.Save(&article)
http.Redirect(w, r, "/", 301)
}
}
func Delete(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
id := r.URL.Query().Get("id")
var article Article
utility.Db.First(&article, id)
tmpl.ExecuteTemplate(w, "delete.html", article)
} else if r.Method == "POST" {
id := r.FormValue("id")
utility.Db.Delete(&Article{}, id)
http.Redirect(w, r, "/", 301)
}
}
CRUDの各処理の記述量がかなり減りました。
データの取得
レコードの取得|GORM
IndexにてFind関数を使い、構造体の形でデータを全件取得しています。
またIdを参照して1件取得する時はFirst関数を使います。
データの作成
レコードの作成|GORM
Create関数に構造体を渡すことでデータを作成できます。
データの更新
レコードの更新|GORM
まずはFirst関数でデータを1件取得し、各カラムを更新、Save関数でデータの更新を行います。
データの削除
レコードの削除|GORM
Delete関数にテーブルと主キー(Id)を指定してデータを削除します。
参考
Discussion