LoginSignup
4
2

More than 3 years have passed since last update.

【Go】DBへのRead/Writeでエンドポイントを分けたい

Posted at

はじめに

レプリケーションに対応するため、DBのエンドポイントをRead/Writeで分けることにしました。
Go/Gorm2でどのように対応するか検討しました。

利用環境

  • Go: 1.15.2
  • Gorm2: v1.20.1
  • Echo: v4.1.17

結論から

Endpoint別に複数のConnectionを持ったTypeに、Gormの各Methodをラップした。
こうすることで、connectionを利用する側はendpointを意識せずにDBへの操作を可能にしています。

db/connect.go
package db

import (
    "os"

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

type SqlHandler struct {
    ReadConn  *gorm.DB
    WriteConn *gorm.DB
}

func Connect() *SqlHandler {
    readConn, err := gorm.Open(GetDBConfig("read"))
    if err != nil {
        panic(err.Error())
    }

    writeConn, err := gorm.Open(GetDBConfig("write"))
    if err != nil {
        panic(err.Error())
    }

    sqlHandler := SqlHandler{
        ReadConn:  readConn,
        WriteConn: writeConn,
    }

    return &sqlHandler
}

func GetDBConfig(endpoint string) (gorm.Dialector, *gorm.Config) {
    USER := "myUser"
    PASS := "hoge1234"
    PROTOCOL := "tcp(" + endpoint + ":5050)"
    DBNAME := "myDB"
    OPTION := "charset=utf8&parseTime=True&loc=Local"

    mysqlConfig := mysql.Config{
        DSN: USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME + "?" + OPTION,
    }

    config := &gorm.Config{}

    return mysql.New(mysqlConfig), config
}

func (handler *SqlHandler) Find(out interface{}, where ...interface{}) *gorm.DB {
    return handler.ReadConn.Find(out, where...)
}

func (handler *SqlHandler) Exec(sql string, values ...interface{}) *gorm.DB {
    return handler.WriteConn.Exec(sql, values...)
}

func (handler *SqlHandler) First(out interface{}, where ...interface{}) *gorm.DB {
    return handler.ReadConn.Find(out, where...)
}

func (handler *SqlHandler) Raw(sql string, values ...interface{}) *gorm.DB {
    return handler.WriteConn.Raw(sql, values...)
}

func (handler *SqlHandler) Create(value interface{}) *gorm.DB {
    return handler.WriteConn.Create(value)
}

func (handler *SqlHandler) Save(value interface{}) *gorm.DB {
    return handler.WriteConn.Save(value)
}

func (handler *SqlHandler) Delete(value interface{}) *gorm.DB {
    return handler.WriteConn.Delete(value)
}

func (handler *SqlHandler) Where(query interface{}, args ...interface{}) *gorm.DB {
    return handler.WriteConn.Where(query, args...)
}

レプリケーション

is 何

レプリケーション

気になる所

func Execfunc Rawなど、queryそのものが発行できる部分については、read/write双方の可能性があり、どちらに振り分けるか悩むところです。
今回はwriteに振り分けました。なるべく利用者はendpointを意識せずに使えるようにしたい...

おわりに

CQRSを利用することを決めており、そもそもSQLベタ書きが増えそうな気がしています。
Gormを使う意味が少し薄れますが、やはりORMとしてのTypeへのマッピングを考えると欲しいところ。
マッピング部分だけ自作したりすると良いのかなと思います!!

参考

4
2
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
4
2