In order to support replication, I decided to divide the DB endpoint by Read / Write. I examined how to handle it with Go / Gorm2.
Each Method of Gorm is wrapped in a Type that has multiple Connections for each Endpoint. By doing this, the side using the connection can operate the DB without being aware of the endpoint.
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...)
}
Replication (https://ja.wikipedia.org/wiki/%E3%83%AC%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82 % B7% E3% 83% A7% E3% 83% B3)
For the parts that can be issued by query itself, such as func Exec and func Raw, there is a possibility of both read / write, and I am wondering which one to distribute.
This time, I assigned it to write. As much as possible, users want to be able to use it without being aware of endpoints ...
I have decided to use CQRS, and I feel that SQL solid writing is likely to increase in the first place. The meaning of using Gorm is a little diminished, but I would like it when considering the mapping to Type as an ORM. I think it would be good to make only the mapping part by yourself! !!
-Golang --Building Clean Architecture API with Echo and GORM
Recommended Posts