はじめに
レプリケーションに対応するため、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 Exec
や func Raw
など、queryそのものが発行できる部分については、read/write双方の可能性があり、どちらに振り分けるか悩むところです。
今回はwriteに振り分けました。なるべく利用者はendpointを意識せずに使えるようにしたい...
おわりに
CQRSを利用することを決めており、そもそもSQLベタ書きが増えそうな気がしています。
Gormを使う意味が少し薄れますが、やはりORMとしてのTypeへのマッピングを考えると欲しいところ。
マッピング部分だけ自作したりすると良いのかなと思います!!