How to create a Singleton DB class in GoLang

EDITED Solved . How to create a single DBManager class in GoLang.

I have referenced several code examples on how to create go singleton, but I want to have methods in them and call them a reference to one single. My code is as follows

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 } 

With a new answer, I updated this question, including the answer. But I have few requests. How to cathc and return an exception from gorm.Create (..)

+5
source share
1 answer

One way is to create an exported interface using methods and make the implementation type non-return. Create a global variable of the interface type and initialize it using the init() package function. You do not need synchronization, since the init() function of the package will only work once, safely.

The functions of the init() package are executed once, automatically, at runtime, before you can reference anything from the package. See Spec: Package Initialization for more details.

For instance:

 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 } 

Using it:

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

You can also do this without the init() function, for example:

 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} } 

With this, you can decide to export newManager() , and your package users can decide to use a common Mgr instance, otherwise they can create another Manager , for example. for testing purposes.

Notes. Mgr is an exported global variable and can be assigned to other packages (for example, dbprovider.Mgr = nil ). If you want to avoid this, you must make it unexcited and provide the getter function for it, for example:

 var mgr = newManager() func Mgr() Manager { return mgr } 

And using it:

 err := dbprovider.Mgr().AddArticle(someArticle) 
+9
source

Source: https://habr.com/ru/post/1261631/