如何创建单例数据库实例

How to create singleton DB instance

我提到了一些关于如何创建 go 单例的代码示例,但我希望在其中包含方法并在其单例引用中调用它们。我的代码如下

package dbprovider

import (
    "github.com/jinzhu/gorm"
    _"github.com/jinzhu/gorm/dialects/sqlite"
    "rest/article"
    "log"
)

type DBOperations interface {
    AddArticle(article *article.Article)
}

type DBManager struct {
    db            *gorm.DB
    isInitialized bool
}

var dbManagerInstance = new()

func GetDBManager() DBManager {
    return dbManagerInstance
}

func new() DBManager {
    localDbRef, err := gorm.Open("sqlite3", "../articles.db")
    if (err != nil) {
        panic("Error initializing db")
    } else {
        log.Print("DB Initialized successfully")
    }
    return DBManager{db:localDbRef, isInitialized:true}
}

func (dbManager DBManager)  AddArticle(article article.Article) (err error) {
    if (dbManager.isInitialized) {
        tx := dbManager.db.Begin()
        //dbManager.db.NewRecord(article)
        //dbManager.db.Commit()
        tx.NewRecord(article)
        tx.Commit()
        errs := dbManager.db.GetErrors()
        if (len(errs) > 0) {
            err = errs[0]
        } else {
            log.Print("No error in this transactions")
        }

    }
    return
}

有了新答案,我更新了这个问题,包括答案。但我有几个疑问。如何从 gorm.Create(..)

中 cathc 和 return 异常

一种方法是使用方法创建导出接口,并使实现类型不导出。创建一个接口类型的全局变量,并用packageinit()函数初始化。您不需要任何同步,因为包 init() 函数将 运行 安全地仅一次。

init() 函数在 运行 之前自动执行一次,然后您可以从包中引用任何内容。有关详细信息,请参阅 Spec: Package initialization

例如:

package dbprovider

type Manager interface {
    AddArticle(article *article.Article) error
    // Add other methods
}

type manager struct {
    db *gorm.DB
}

var Mgr Manager

func init() {
    db, err := gorm.Open("sqlite3", "../articles.db")
    if err != nil {
        log.Fatal("Failed to init db:", err)
    }
    Mgr = &manager{db: db}
}

func (mgr *manager) AddArticle(article *article.Article) (err error) {
    mgr.db.Create(article)
    if errs := mgr.db.GetErrors(); len(errs) > 0 {
        err = errs[0]
    }
    return
}

使用它:

import "dbprovider"

if err := dbprovider.Mgr.AddArticle(someArticle); err != nil {
    // Handle error
}

你也可以不使用 init() 函数,例如:

var Mgr = newManager()

func newManager() Manager {
    db, err := gorm.Open("sqlite3", "../articles.db")
    if err != nil {
        log.Fatal("Failed to init db:", err)
    }
    return &manager{db: db}
}

有了这个,您可以决定导出 newManager(),您的包的用户可以决定使用共享的 Mgr 实例,或者他们可以创建另一个 Manager,例如用于测试目的。

注: Mgr是一个导出的全局变量,可以被其他包赋值给它(例如dbprovider.Mgr = nil) .如果你想避免这种情况,你必须让它不被导出,并为它提供一个 "getter" 函数,例如:

var mgr = newManager()

func Mgr() Manager { return mgr }

并使用它:

err := dbprovider.Mgr().AddArticle(someArticle)