单例模式-数据库单例
最后更新于:2022-04-02 02:35:36
[TOC]
> [参考](https://tonybai.com/2021/02/09/create-and-get-db-access-instance-through-singleton/)
## db 案例
main.go
```
package main
import (
"log"
"os"
"os/signal"
"sync"
"syscall"
"github.com/bigwhite/testdboper/pkg/config"
"github.com/bigwhite/testdboper/pkg/db"
"github.com/bigwhite/testdboper/pkg/reader"
"github.com/bigwhite/testdboper/pkg/updater"
)
func init() {
err := config.Init() // 初始化配置
if err != nil {
panic(err)
}
}
func main() {
var wg sync.WaitGroup
wg.Add(2)
var quit = make(chan struct{})
// do some init from db
_ = db.DB()
go func() {
updater.Run(quit)
wg.Done()
}()
go func() {
reader.Run(quit)
wg.Done()
}()
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
_ = <-c
close(quit)
log.Printf("recv exit signal...")
wg.Wait()
log.Printf("program exit ok")
}
```
db.go
```
package db
import (
"fmt"
"sync"
"time"
"github.com/bigwhite/testdboper/pkg/config"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
var once sync.Once
type database struct {
instance *gorm.DB
maxIdle int
maxOpen int
maxLifetime time.Duration
}
type Option func(db *database)
var db *database
func WithMaxIdle(maxIdle int) Option {
return func(d *database) {
d.maxIdle = maxIdle
}
}
func WithMaxOpen(maxOpen int) Option {
return func(d *database) {
d.maxOpen = maxOpen
}
}
func DB(opts ...Option) *gorm.DB {
once.Do(func() {
db = new(database)
for _, f := range opts {
f(db)
}
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local",
config.Config.Database.User,
config.Config.Database.Password,
config.Config.Database.IP,
config.Config.Database.Port,
config.Config.Database.DB)
var err error
db.instance, err = gorm.Open("mysql", dsn) // database: *gorm.DB
if err != nil {
panic(err)
}
sqlDB := db.instance.DB()
if err != nil {
panic(err)
}
if db.maxIdle != 0 {
sqlDB.SetMaxIdleConns(db.maxIdle)
}
if db.maxLifetime != 0 {
sqlDB.SetConnMaxLifetime(db.maxLifetime)
}
if db.maxOpen != 0 {
sqlDB.SetMaxOpenConns(db.maxOpen)
}
})
// 核心代码,初始化后,在返回实例
return db.instance
}
```
reader.go
```
package reader
import (
"log"
"time"
"github.com/bigwhite/testdboper/pkg/db"
"github.com/bigwhite/testdboper/pkg/model"
)
func dumpEmployee() {
var rs []model.Employee // rs: record slice
d := db.DB()
d.Find(&rs)
log.Println(rs)
}
func Run(quit <-chan struct{}) {
tk := time.NewTicker(5 * time.Second)
for {
select {
case <-tk.C:
dumpEmployee()
case <-quit:
return
}
}
}
```
';