0
0

GoのGORMを使ってみる

Posted at

はじめに

Gormって使ったことありますか?
Goでは、コードないにsqlクエリを書いてgithub.com/go-sql-driver/mysqlを使えば、データベース操作が行えると思います。

しかし、Djangoなどのmodelを定義するだけでデータベース操作が行えてしまうフレームワークのみを過去に触っていた人は、sqlクエリの書き方がわからず苦戦すると思います。
それにいくらsqlが書けたとしても、長々とsqlを書きたくないですよね。

なので、今回はそれを解決するGORMを使ってみようと思います。

GORMとは

GORMとは、Go言語のORMライブラリです。

ORMって言われてもわからないですよね。

まずはORMから説明します。

ORMとは

オブジェクト関係マッピング(Object-Relational Mapping)の略称で、オブジェクト指向におけるクラスや構造体とデータベースを紐付ける技術のことを指します。Djangoでモデルを定義するだけで、データベース操作が行えたのは標準でORMが使われていたからです。

メリット

  • オブジェクト指向におけるクラスを使った再利用性が高いこと
  • クエリの自動生成があるため簡単に操作できる

デメリット

  • sqlクエリとは異なり、言語やライブラリ毎に知識を得ることが必要
  • 複雑な操作はクエリを学ぶ必要がある

という感じだと思います。

個人的には、クエリ書く方がどこでも使えますし、実際にmysql-clientとかでデータベースの中身に入ってデータを確認する時には必要なので好きです。ただ自分はsql書くよりも先にDjangoを触ってORMによるデータベース操作ORMの存在を全く理解せずに使って、楽であることは痛感したので良い技術だなと感じています。

環境を作る

Dockerでの環境

今回は、Dockerでmysqlコンテナを立ち上げていこうと思います。
docker-compose.ymlを下のように記述します。

docker-compose.yml
services:
  db:
    image: mysql:8.0
    container_name: mysql_gorm
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    ports:
      - "3306:3306"
    volumes:
      - db-volume:/var/lib/mysql

volumes:
  db-volume:

あとは下のコマンドを打ちます。

docker-compose.yml

コンソールに下のような文言があれば立ち上がっています。

mysql_gorm  | 2024-08-15T02:58:51.493939Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.38'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.

この文言判断しづらいので、mysqlコンテナの中に入ってdbを操作できるか試した方が良さそうです。

GOでの環境

Goでのセットアップを行います。

Goのモジュールを以下のように初期化します。

go mod init <モジュール名>

モジュール名は自由に決めることが可能なので、私は下のようにしました。

go mod init github.com/maooz4426/go_gorm

GORMをインストールします

go get -u gorm.io/gorm

ここまで来たらコードを書いてみようと思います。

コードを書いてみる

レコードを入れる

下にPersonというスキーマを定義して、それをマイグレート、Jackさんのレコードを挿入した後にJackさんのレコードを取得するようなコードを書いてみました。

main.go
package main
package main

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

type Person struct {
	gorm.Model
	Name string
	Age  int
}

func main() {
	dsn := "user:password@tcp(localhost:3306)/db?parseTime=true"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatal("mysql can not open:", err)
	}

	db.AutoMigrate(&Person{})

	db.Create(&Person{
		Name: "jack",
		Age:  21,
	})

	var person Person

	result := db.First(&person, 1)
	if result.Error != nil {
		log.Fatal(result.Error)
	}
	fmt.Println(person.Name)
}


GORMを使う場合、gormモジュールと使うデータベースようのドライバーが必要になります。なので今回は、gorm.io/driver/mysqlgorm.io/gormをインポートしています。

DSNをdocker-compose.ymlで書いた環境変数から設定します。

DSNとは
DataSorceNAMEのことで、データベース接続のために必要な識別子のことです

時間はbyte型で、GORMのcreated_at等の時間に関するカラムはtime.Time型となっていて、型が違うためparseTime=trueをつけないとデータが取れないのでつけてください。

そこからOpenメソッドでデータベースを接続します。

AutoMigrateメソッドでは、マイグレーションを自動で行っています。

マイグレーションとは
データベースのスキーマ(構造)の更新を行うこと。
例えば、Userテーブルに利き手というカラム(要素)が追加されたら、それをデータベースに適応させる作業のことを言う

Createメソッドでレコードを作成しています。

Firstメソッドでは、レコードの読み込みを行なっており、primary-keyが1であるレコードをPerson型の変数personに読み込んでいます。

Firstメソッドでは、読み取った値を変数に入れて使う必要があります。

実行してみると、

go run main.go
jack

うまく動作しました!

ここでmysqlの中に入ってみようと思います。
Docker Desktopの立ち上げたコンテナを選択して下のような画面に移動します。
スクリーンショット 2024-08-15 19.13.22.png

このターミナルに下のコマンドでmysqlに入ります。

mysql -h localhost -u user -p 

すると下のようにpasswordを入力するように言われるのでdocker-compose.ymlに入力した環境変数のpasswordを使用します。

sh-5.1# mysql -h localhost -u user -p
Enter password: 

passwordが入力成功すると下のようになります。

mysql> 

そこから下のクエリを入力して行って、テーブルがどうなってるか確認します。

use db

show tables;

すると下のように表示されます。

+--------------+
| Tables_in_db |
+--------------+
| people       |
+--------------+

構造体でPersonと指定したのに、なぜかPeopleになっています。
GORMでは標準でテーブル名が複数形になります。

なのでここからレコードを確認するには、Personの複数形であるPeopleをテーブルで指定する必要があります。

mysql> SELECT * FROM people;
+----+-------------------------+-------------------------+-------------------------+------+------+
| id | created_at              | updated_at              | deleted_at              | name | age  |
+----+-------------------------+-------------------------+-------------------------+------+------+
|  1 | 2024-08-15 09:58:13.661 | 2024-08-15 10:00:35.084 | 2024-08-15 10:05:54.017 | jack |   21 |
+----+-------------------------+-------------------------+-------------------------+------+------+

レコードを更新する

次にupdateしてみようと思います.

下のようにCreateメソッドをコメントアウトして、名前をJackからKenyに変えるコードを書いてみました。

main.go
package main

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

type Person struct {
	gorm.Model
	Name string
	Age  int
}

func main() {
	dsn := "user:password@tcp(localhost:3306)/db?parseTime=true"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatal("mysql can not open:", err)
	}

	db.AutoMigrate(&Person{})

	//db.Create(&Person{
	//	Name: "jack",
	//	Age:  21,
	//})

	db.Model(&Person{}).Where(1).Update("name", "Keny")

	var person Person

	result := db.First(&person, 1)
	if result.Error != nil {
		log.Fatal(result.Error)
	}
	fmt.Println(person.Name)
}

db.Model(&Person{}).Where(1).Update("name", "Keny")の部分はクエリだと下と同じことを行なっています。

Update people SET name="Keny"

実行結果は下のようになり変わったようです。

go run main.go
Keny

レコードを削除する

次はレコードを削除してみようと思います。
下のコードのように、いくつかコードをコメントアウトして、KenyのレコードをDeleteメソッドで削除しようと思います。

main.go
package main

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

type Person struct {
	gorm.Model
	Name string
	Age  int
}

func main() {
	dsn := "user:password@tcp(localhost:3306)/db?parseTime=true"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatal("mysql can not open:", err)
	}

	db.AutoMigrate(&Person{})

	//db.Create(&Person{
	//	Name: "jack",
	//	Age:  21,
	//})

	//db.Model(&Person{}).Where(1).Update("name", "Keny")

	db.Delete(&Person{}, 1)

	var person Person

	result := db.First(&person, 1)
	if result.Error != nil {
		log.Fatal(result.Error)
	}

	fmt.Println(person.Name)
}

実行してみます。

go run main.go

2024/08/15 19:05:54 /Users/maoz/Documents/Go/go_grom/main.go:36 record not found
[0.643ms] [rows:0] SELECT * FROM `people` WHERE `people`.`id` = 1 AND `people`.`deleted_at` IS NULL ORDER BY `people`.`id` LIMIT 1
2024/08/15 19:05:54 record not found
exit status 1

削除できたようです。

最後に

ORMはとても便利で使いやすいのでぜひGoで開発している方は使ってみてください。
自分はsqlの知識が足りないので当分はクエリをコードに書いて行おうと思います。

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