Совместное использование глобальной связи db с несколькими пакетами в Голанге
Я прочитал несколько ответов StackOverflow о том, как мы обрабатываем соединение db. Поскольку это пул, мы можем определить его во всем мире и использовать его в нескольких гортанах, и это безопасно.
Проблема, с которой я сталкиваюсь, заключается в том, что я разделил REST API на несколько пакетов. Для каждого из этих пакетов требуется соединение db, поэтому я открываю соединение с базой данных при запуске. Но даже если я определяю соединение по всему миру, это только на уровне пакета. Что я могу сделать, чтобы потенциально поделиться им между несколькими пакетами?
В каком-то контексте я использую драйвер PostgreSQL и gin-gonic в своем приложении.
Ответы
Ответ 1
Существует также возможность создания другого пакета для хранения настроек, связанных с подключением к базе данных. Затем он может иметь глобальный уровень пакета, который можно инициализировать в main
и использовать в любом пакете, который его импортирует.
Таким образом, вы можете явно видеть, что пакет базы данных импортируется. Вот пример кода.
package database
var (
// DBCon is the connection handle
// for the database
DBCon *sql.DB
)
package main
import "myApp/database"
func main() {
var err error
database.DBCon, err = sql.Open("postgres", "user=myname dbname=dbname sslmode=disable")
}
package user
import "myApp/database"
func Index() {
// database handle is available here
database.DBCon
...
}
Ответ 2
Простой ответ: передайте инициализированный пул соединений в свои глобальные глобальные пакеты.
например
// package stuff
var DB *sql.DB
func GetAllStuff() (*Stuff, error) {
err := DB.Query("...")
// etc.
}
// package things
var DB *sql.DB
func GetAllThings() (*Thing, error) {
err := DB.Query("...")
// etc.
}
// package main
func main() {
db, err := sql.Open("...")
if err != nil {
log.Fatal(err)
}
stuff.DB = db
things.DB = db
// etc.
}
Мы определяем глобальные глобальные уровни пакета, убедитесь, что они экспортированы (заглавные), а затем передают указатель на наш пул соединений.
Это "хорошо", но может маскировать "where" вещи используются. Если вы посмотрите на обработчик, может быть неясно, откуда происходит соединение, особенно по мере роста вашего пакета. Более масштабируемый подход может выглядеть следующим образом:
// package stuff
type DB struct {
*sql.DB
}
func New(db *sql.DB) (*DB, error) {
// Configure any package-level settings
return &DB{db}, nil
}
func (db *DB) GetAllStuff() (*Stuff, error) {
err := db.Query("...")
// etc.
}
// package things
type DB struct {
*sql.DB
}
func New(db *sql.DB) (*DB, error) {
// Configure any package-level settings
return &DB{db}, nil
}
func (db *DB) GetAllThings() (*Thing, error) {
err := db.Query("...")
// etc.
}
// package main
func main() {
db, err := sql.Open("...")
if err != nil {
log.Fatal(err)
}
stuffDB, err := stuff.New(db)
if err != nil {
log.Fatal(err)
}
thingsDB, err := things.New(db)
if err != nil {
log.Fatal(err)
}
// Simplified.
http.HandleFunc("/stuff/all", stuff.ShowStuffHandler(stuffDB))
http.HandleFunc("/things/all", things.ShowThingsHandler(thingsDB))
// etc.
}
func ShowStuffHandler(db *stuff.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// We can use our stuff.DB here
stuff, err := db.GetAllStuff()
// etc.
}
}
Если у вас больше, чем просто соединение с DB в качестве зависимости (например, параметры конфигурации, имена хостов и т.д.), things.Env
их в структуру things.Env
или структуру stuff.Env
для каждого пакета.
Примером может быть наличие things.New("deps...") *Env
которая возвращает настроенные *things.Env
которые содержат зависимости, используемые вашим пакетом things
.