如何在GoLang中创建单例数据库类

时间:2016-12-21 08:01:27

标签: go go-gorm singleton-methods

已编辑 已解决:如何在GoLang中创建单例DBManager类。

我提到了如何创建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并返回异常

1 个答案:

答案 0 :(得分:13)

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

程序包init()函数由运行时自动执行一次,然后才能从程序包中引用任何内容。有关详细信息,请参阅Spec: Package initialization

例如:

init()

使用它:

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)。如果你想避免这种情况,你必须使它成为未导出的,并提供一个" getter"它的功能,例如:

dbprovider.Mgr = nil

使用它:

var mgr = newManager()

func Mgr() Manager { return mgr }