【问题标题】:How to create singleton DB instance如何创建单例数据库实例
【发布时间】:2017-05-06 14:03:48
【问题描述】:

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

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(..) 捕获并返回异常

【问题讨论】:

    标签: go singleton go-gorm


    【解决方案1】:

    一种方法是使用方法创建导出接口,并使实现类型不导出。创建接口类型的全局变量,并使用包init()函数对其进行初始化。您不需要任何同步,因为包 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)
    

    【讨论】:

    • 从哪里调用这个 init 方法?
    • @sector11 Package init() 函数由运行时自动执行一次,然后您才能引用包中的任何内容。请参阅编辑后的答案。
    • 获取不能使用 localDbRef (type *gorm.DB) 作为类型 gorm.DB in field value
    • @sector11 多次编辑代码,确保使用当前版本。如果仍然无法正常工作,请发布您的版本。
    • 已经更新了我的问题,你回答我现在想知道的是如果创建函数失败,如何从创建函数中获取错误。
    猜你喜欢
    • 1970-01-01
    • 2013-04-14
    • 1970-01-01
    • 1970-01-01
    • 2014-01-13
    • 1970-01-01
    • 2014-06-20
    • 2018-09-26
    • 1970-01-01
    相关资源
    最近更新 更多