2016-12-21 3 views
4

EDITEDРешено: Как создать одиночный класс DBManager в GoLang.Как создать singleton DB класс в GoLang

Я ссылался на несколько примеров кода, как создать go singleton, но я хочу иметь в них методы и называть их ссылкой на один синглтон. Мой код выглядит следующим образом

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 
} 

С новым ответом я обновил этот вопрос, включая ответ. Но у меня мало запросов. Как cathc и возвращать исключение из gorm.Create (..)

ответ

7

Один из способов - создать экспортированный интерфейс с помощью методов и сделать тип реализации невозвращенным. Создайте глобальную переменную типа интерфейса и инициализируйте ее пакетом 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() Экспортированные и пользователи вашего пакета могут решить использовать sh isd Mgr, или они могли бы создать еще один Manager, например. для целей тестирования.

Примечание:Mgr является глобальным переменным экспортируются, и можно присвоить новое значение к нему другим пакетам (например dbprovider.Mgr = nil). Если вы хотите, чтобы избежать этого, вы должны сделать его неэкспортируемым, и обеспечивает функцию «геттер» для него, например:

var mgr = newManager() 

func Mgr() Manager { return mgr } 

и его использование:

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

откуда этот метод инициализации получает называется? – sector11

+0

@ sector11 Пакет 'init()' функции выполняются один раз автоматически, по времени выполнения, прежде чем вы сможете ссылаться на что-либо из пакета. См. Отредактированный ответ. – icza

+0

Получение не может использовать localDbRef (тип * gorm.DB) как тип gorm.DB в поле значение – sector11

Смежные вопросы