使用通道
import(
"database/sql"
_"github.com/go-sql-driver/mysql"
"log"
"time"
"math/rand"
)
// 連接池大小
var MAX_POOL_SIZE = 20
var dbPoll chan *sql.DB
const (
user="root"
pass="root"
db="school"
)
func putDB(db *sql.DB) {
// 基于函數(shù)和接口間互不信任原則摘昌,這里再判斷一次诗眨,養(yǎng)成這個好習(xí)慣哦
if dbPoll == nil {
dbPoll = make(chan *sql.DB, MAX_POOL_SIZE)
}
if len(dbPoll) >= MAX_POOL_SIZE {
db.Close()
return
}
dbPoll <- db
}
func initDB() {
// 緩沖機(jī)制,相當(dāng)于消息隊列
if len(dbPoll) == 0 {
// 如果長度為0掌腰,就定義一個redis.Conn類型長度為MAX_POOL_SIZE的channel
dbPoll = make(chan *sql.DB, MAX_POOL_SIZE)
go func() {
for i := 0; i < MAX_POOL_SIZE/2; i++ {
db,err:=sql.Open("mysql",user+":"+pass+"@tcp(localhost:3306)/"+db+"?charset=utf8")
if err!=nil {
log.Println(err)
}
putDB(db)
}
} ()
}
}
func GetDB() *sql.DB {
//如果為空就初始化或者長度為零
if dbPoll == nil||len(dbPoll) == 0{
initDB()
}
return <- dbPoll
}
自己寫的連接池
db.go
package db
import (
"time"
"github.com/Sirupsen/logrus"
"github.com/jinzhu/gorm"
_"github.com/go-sql-driver/mysql"
"reflect"
"fmt"
"errors"
"strconv"
"youguoju/conf/config"
)
type dB interface {
Gorm()*gorm.DB
Id()uint32//ID的獲取方法
}
type myDB struct {
db *gorm.DB
id uint32//ID
}
type DBPoll interface {
Take()(dB,error)//取出實體
Return(entity dB)(error)//歸還實體
Total()uint32//實體的容量
Used()uint32//實體中已經(jīng)被使用的實體數(shù)量
}
type myDBPoll struct {
pool DBPoll //實體池
etype reflect.Type //池內(nèi)實體的類型
}
//生成DB的函數(shù)類型
type genDB func() dB
func newDBPoll(total uint32,gen genDB)(DBPoll,error) {
etype:=reflect.TypeOf(gen())
genEntity:= func() dB{return gen()}
pool,err:= NewPool(total,etype,genEntity)
if err!=nil {
return nil,err
}
dbpool:=&myDBPoll{pool,etype}
return dbpool,nil
}
func (db *myDB)Id()uint32 {
return db.id
}
func (db *myDB)Gorm()*gorm.DB {
return db.db
}
//取出實體
func (pool *myDBPoll)Take()(dB,error){
entity,err:=pool.pool.Take()
if err!=nil {
return nil,err
}
dl,ok:=entity.(dB)//強制類型轉(zhuǎn)換
if !ok {
errMsg:=fmt.Sprintf("The type of entity id NOT %s\n",pool.etype)
panic(errors.New(errMsg))
}
return dl,nil
}
//歸還實體
func (pool *myDBPoll)Return(entity dB)(error){
return pool.pool.Return(entity)
}
//實體的容量
func (pool *myDBPoll)Total()uint32{
return pool.pool.Total()
}
//實體中已經(jīng)被使用的實體數(shù)量
func (pool *myDBPoll)Used()uint32{
return pool.pool.Used()
}
var dbPoll DBPoll
func InitDB() {
total := config.Conf.Total
to,_:=strconv.Atoi(total)
dbPoll,_=newDBPoll(uint32(to),initDb)
}
//func GetDBPollInstance() DBPoll {
// return dbPoll
//}
func GetDBInstance() (dB,error) {
db,err:=dbPoll.Take()
if err!=nil {
return nil, err
}
return db,nil
}
func ReturnDB(db dB) error {
return dbPoll.Return(db)
}
func initDb() dB{
var db *gorm.DB
var err error
path := config.Conf.DBURL //從env獲取數(shù)據(jù)庫連接地址
logrus.Info("path:", string(path)) //打印數(shù)據(jù)庫連接地址
for {
db, err = gorm.Open("mysql", string(path)) //使用gorm連接數(shù)據(jù)庫
if err != nil {
logrus.Error(err, "Retry in 2 seconds!")
time.Sleep(time.Second * 2)
continue
}
logrus.Info("DB connect successful!")
break
}
return &myDB{db:db,id:idGenertor.GetUint32()}
}
var idGenertor IdGenertor = NewIdGenertor()
pool.go
package db
import (
"reflect"
"fmt"
"errors"
"sync"
)
type Pool interface {
Take()(dB,error)//取出實體
Return(entity dB)(error)//歸還實體
Total()uint32//實體的容量
Used()uint32//實體中已經(jīng)被使用的實體數(shù)量
}
////實體的接口類型
//type Entity1 interface {
// Id()uint32//ID的獲取方法
//}
//實體池的實現(xiàn)類型
type myPool struct {
total uint32//池的總?cè)萘? etype reflect.Type//池中實體的類型
genEntity func()dB//池中實體的生成函數(shù)
container chan dB//實體容器
//實體Id的容器
idContainer map[uint32]bool
mutex sync.Mutex
}
func NewPool(total uint32,entityType reflect.Type,genEntity func()dB)(Pool,error) {
if total==0 {
errMsg:=fmt.Sprintf("The pool can not be initialized! (total=%d)\n",total)
return nil,errors.New(errMsg)
}
size:=int(total)
container:=make(chan dB,size)
idContainer:=make(map[uint32]bool)
for i:=0;i<size ; i++ {
newEntity:=genEntity()
if entityType!=reflect.TypeOf(newEntity) {
errMsg:=fmt.Sprintf("The type of result of function gen Entity()is Not %s\n",entityType)
return nil,errors.New(errMsg)
}
container<-newEntity
idContainer[newEntity.Id()]=true
}
pool:=&myPool{total,entityType,genEntity,container,idContainer,*new(sync.Mutex)}
return pool,nil
}
//取出實體
func (pool *myPool)Take()(dB,error){
entity,ok:=<-pool.container
if !ok {
return nil,errors.New("The innercontainer is invalid")
}
pool.mutex.Lock()
defer pool.mutex.Unlock()
pool.idContainer[entity.Id()]=false
return entity,nil
}
//歸還實體
func (pool *myPool)Return(entity dB)(error){
if entity==nil {
return errors.New("The returning entity is invalid")
}
if pool.etype!=reflect.TypeOf(entity) {
errMsg:=fmt.Sprintf("The type of result of function gen Entity()is Not %s\n",pool.etype)
return errors.New(errMsg)
}
entityId:=entity.Id()
caseResult:=pool.compareAndSetForIdContainer(entityId,false,true)
if caseResult==-1 {
errMsg:=fmt.Sprintf("The entity(id=%d) is illegal!\n",entity.Id())
return errors.New(errMsg)
}
if caseResult==0 {
errMsg:=fmt.Sprintf("The entity(id=%d) is already in the pool!\n",entity.Id())
return errors.New(errMsg)
}else {
pool.idContainer[entityId]=true
pool.container<-entity
return nil
}
}
//比較并設(shè)置實體ID容器中與給定實體ID對應(yīng)的鍵值對的元素值
//結(jié)果值;1操作成功
// 0.對應(yīng)的id在容器中已經(jīng)存在
// -1.對應(yīng)的id在容器中不存在
//
func (pool *myPool) compareAndSetForIdContainer(entityId uint32,oldValue,newValue bool)int8 {
pool.mutex.Lock()
defer pool.mutex.Unlock()
v,ok:=pool.idContainer[entityId]
if !ok {
return -1
}
if v!=oldValue {
return 0
}
pool.idContainer[entityId]=newValue
return 1
}
//實體的容量
func (pool *myPool)Total()uint32{
return uint32(cap(pool.container))
}
//實體中已經(jīng)被使用的實體數(shù)量
func (pool *myPool)Used()uint32{
return uint32(cap(pool.container)-len(pool.container))
}
id生成器
package db
import (
"sync"
"math"
)
type IdGenertor interface {
GetUint32() uint32//獲取一個unit32類型的Id
}
type cyclicIdGenertor struct {
id uint32//當(dāng)前id
ended bool//簽一個id是否為其類型所能表示的做大值
mutex sync.Mutex
}
func NewIdGenertor() IdGenertor {
return &cyclicIdGenertor{}
}
//獲取一個unit32類型的Id
func (gen *cyclicIdGenertor)GetUint32() uint32 {
gen.mutex.Lock()
defer gen.mutex.Unlock()
if gen.ended {
defer func() {gen.ended=false}()
gen.id=uint32(1)
return uint32(0)
}
id:=gen.id
if id<math.MaxInt32{
gen.id++
}else {
gen.ended=true
}
return id
}
type cyclicIdGenertor2 struct {
base cyclicIdGenertor//基本id生成器
cycleCount uint64//基于unit32類型的取值范圍的周期計數(shù)
}
//獲取一個unit64類型的Id
func (gen *cyclicIdGenertor2)GetUint64() uint64{
var id64 uint64
if gen.cycleCount%2==1 {
id64+=math.MaxUint32
}
id32:=gen.base.GetUint32()
if id32==math.MaxInt32 {
gen.cycleCount++
}
id64+=uint64(id32)
return id64
}
使用
//利用token從數(shù)據(jù)庫庫中獲取用戶信息
func (user *User)GetUserByTokenFromDB(token string)(bool) {
instance,err:=db.GetDBInstance()
defer db.ReturnDB(instance)
if err!=nil {
return false
}
gorm:=instance.Gorm()
gorm.Where("Token = ?", token).Find(&user)
return true
}