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?

gorm.DBの構造体の中身の定義はどのようなものになっているのか

Posted at

全体像:gorm.DBは「DB操作の状態+設定」の塊

GROM v2系では,gorm.DBの定義はざっくりというと次のような構造になっている.

type DB struct {
    Config       *Config      // 設定(Logger、DryRun、SkipDefaultTransactionなど)
    Error        error        // 直近のエラー
    RowsAffected int64        // 直近のクエリで影響を受けた行数

    Statement    *Statement   // 実行中のSQLに関する情報(テーブル、条件、値など)
    // 以下、セッション状態・コールバック・フックなど
}

ポイントとして

  • DBは「データベース接続のハンドル」+「直近のクエリ状態」をまとめたもの
  • 内部でさらにConfigやStatementなどの構造体を持っている

主なフィールドの意味

Config *Config

ConfigはGORMの動作設定のこと

具体例

  • 使用するログ(Logger)
  • トランザクションのデフォルト挙動
  • テーブル名の命名規則
  • プリロード(関連取得)の設定
    など

イメージ

type Config struct {
    Logger                 logger.Interface
    SkipDefaultTransaction bool
    NamingStrategy         schema.Namer
    // ...
}

よってよく使われるものとして,

gorm.Open(postgres.Open(dsn), &gorm.Config{})

のなかの,&gorm.Config{}が当たる.
ちなみにこのコードは「GORMでPostgreSQLに接続するためのエンジンをつくる処理」である.

  • dsn:どのDBにどのユーザーでどのパスワードで接続するかを文字列で表したもの
  • Open(dsn):PostgreSQL用のドライバに,このDNSで接続してという設定オブジェクトをつくる.設定オブジェクトとは,プログラムの動作方法(ルール,挙動,オプション)をまとめて一つにしたもの
  • &gorm.Config{}:GORM側の設定で,ログや命名規則などのGORMの挙動を制限する設定の入れ物で,空にするとデフォルト設定になる
  • gorm.Open():引数の二つを組み合わせて,DBに接続できる*gorm.DBオブジェクトを作り,戻り値がdb *gorm.DB, err errorの形で返ってくる

Error error

直近のクエリで発生したエラーがここに入る.

result := db.Find(&items)
if result.Error != nil {
    // ここでエラー処理
}

のresult.Errorは,内部的にgorm.DBのErrorフィールド.

RowsAffected int64

直近のクエリで「何行影響を受けたか」

  • SELECT:取得件数
  • UPDATE/DELETE:更新・削除された件数
var users []User
result := db.Where("age >= ?", 18).Find(&users)
fmt.Println(result.RowsAffected) // 取得できたレコードの件数
result := db.Model(&User{}).Where("active = ?", true).Update("age", 20)
fmt.Println(result.RowsAffected) // 更新された行数
result := db.Where("age < ?", 10).Delete(&User{})
fmt.Println(result.RowsAffected) // 削除された行数

第一引数が構造体のアドレスで,第二引数がid(Primary key)となり,idを用いてWHERE id = ?が生成される.
また,第一引数で&User{}のように型だけ教えるダミーを渡すことも可能.

result := db.Where("age < ?", 10).Delete(&User{})

Statement *Statement

今まさに実行しようとしている(または実行した)SQLの「構成情報」が詰まっている.中には,

  • どのテーブルに対して
  • どの条件で
  • どの値を使って
  • どのカラムを更新するか
  • プレーズホルダとの値の対応

などが入る.

Where(), Model(), Table()などを繋げていくと,このStatementがどんどん組み立てられ,最終的にSQLに変換される.

注釈

プレーズホルダ:SQLの中で,値を直接埋め込ませずに「後から値を入れる穴」を作るための記号のこと

「接続プール」はどこにあるのか

GROMは内部で*sql.DB(Go標準のDB接続プール)を抱えているが,それはgorm.DBからさらに下の層(gorm.io/gorm@schema, gorm.io/driver/postgresなど)に隠蔽されており,直接gorm.DBのフィールドとしては見えていない(ドライバ側の構造体に入っている).
イメージとしては

gorm.DB
  └── Config
  └── Statement
  └── (内部で)gorm.io/driver/postgres の構造体
         └── *sql.DB(接続プール)

という多層構造になっている.

注釈

  • プール:同じ種類の何か(オブジェクトや接続など)を複数まとめて管理し,必要なときに貸し出したり返却したりする仕組み.接続プール(コネクションプール)とは,簡単にいうとメモリのようなもので,DBとの接続は作るのにコストが高い(毎回CONNECT→DISCONECTにする)ので,あらかじめ一定の接続を作っておき,必要な時にその接続を借りて使い,使い終わったら破棄ではなくプールに返すという方式を取る.GORMの内部でdatabase/sqlの*sql.DBを使い,その中で接続プールを管理している.
  • .io:TDL(トップレベルドメイン)の一種で,GORMの公式ドメインとして使われている
  • ドライバ:あるソフトウェア(ここではGORMやdatabase/sql)が特定の外部システム(ここではPostgreSQLなどのDB)とやり取りするための「橋渡し役」.DBの種類ごとにプロトコル(通信するときの決まり事(ルールのセット))が違うためそれを渡す.

なぜgorm.DBが「セッションオブジェト」と呼ばれるか

GORM v2では,dbに対してメソッドチェーンするたびに「新しいセッションを返す」イメージになっている.

db.Where("name = ?", "Taro").Find(&users)

ここで

  • db自体は元の「ベース」
  • db.Where(...)はdbを元にした「条件付きセッション」

そのセッションの状態(条件,モデル,プレロード情報など)がStatementに入っている.

注釈

  • メソッドチェーン:メソッドの戻り値に対してさらにメソッドを呼び続けて,一つの流れとして処理をつなげていく書き方
  • セッション:一連のDB操作の設定や状態をまとめたもので,この一連の操作はこういう設定で実行してくれという単位
  • プレロード情報:プレロードとはテーブルの中の別テーブルのデータも一緒に取ってくることで,どの関連(別テーブル)をプレロードするかという情報をSatementの中に保存する内容のこと
  • Statement:今から実行する(または実行した)SQLに関する情報の塊のこと.GORMはWhere / Model / Table / Select / Order などを呼ぶごとにStatementを組み立て,最後の Find / Create / Update などのタイミングでSQLに変換してDBに投げる.

まとめ

知っておくことは以下のこと

  • gorm.DBは「DB操作のための構造体」
  • *gorm.DBを使うのは「同じ接続・設定・状態を共有するため」
  • 内部的には:
    • Config(ログ・命名規則・挙動設定)
    • Error(直近のエラー)
    • RowsAffected(直近の影響行数)
    • Statement(現在のクエリ状態)
      が入っている.
  • 実際の接続プールはドライバ内部で管理されているので,意識する必要はあまりない.
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?