Совместное использование глобальной связи 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.