golang 創(chuàng)建DB連接池

使用通道

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
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末亭罪,一起剝皮案震驚了整個濱河市咐旧,隨后出現(xiàn)的幾起案子骤铃,更是在濱河造成了極大的恐慌沛善,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驶乾,死亡現(xiàn)場離奇詭異邑飒,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)级乐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進(jìn)店門疙咸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人风科,你說我怎么就攤上這事撒轮。” “怎么了贼穆?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵题山,是天一觀的道長。 經(jīng)常有香客問我故痊,道長顶瞳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任愕秫,我火速辦了婚禮慨菱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘戴甩。我一直安慰自己抡柿,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布等恐。 她就那樣靜靜地躺著洲劣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪课蔬。 梳的紋絲不亂的頭發(fā)上囱稽,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天,我揣著相機(jī)與錄音二跋,去河邊找鬼战惊。 笑死,一個胖子當(dāng)著我的面吹牛扎即,可吹牛的內(nèi)容都是我干的吞获。 我是一名探鬼主播,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼谚鄙,長吁一口氣:“原來是場噩夢啊……” “哼各拷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起闷营,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤烤黍,失蹤者是張志新(化名)和其女友劉穎知市,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體速蕊,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡嫂丙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了规哲。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跟啤。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖唉锌,靈堂內(nèi)的尸體忽然破棺而出隅肥,到底是詐尸還是另有隱情,我是刑警寧澤糊秆,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站议双,受9級特大地震影響痘番,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜平痰,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一汞舱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宗雇,春花似錦昂芜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至舞虱,卻和暖如春欢际,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背矾兜。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工损趋, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人椅寺。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓浑槽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親返帕。 傳聞我的和親對象是個殘疾皇子桐玻,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)荆萤,斷路器畸冲,智...
    卡卡羅2017閱讀 134,717評論 18 139
  • database/sql database/sql是golang的標(biāo)準(zhǔn)庫之一,它提供了一系列接口方法,用于訪問關(guān)系...
    人世間閱讀 39,133評論 5 55
  • 這些屬性是否生效取決于對應(yīng)的組件是否聲明為 Spring 應(yīng)用程序上下文里的 Bean(基本是自動配置的)邑闲,為一個...
    發(fā)光的魚閱讀 1,432評論 0 14
  • application的配置屬性算行。 這些屬性是否生效取決于對應(yīng)的組件是否聲明為Spring應(yīng)用程序上下文里的Bea...
    新簽名閱讀 5,381評論 1 27
  • 從小到大,記不得多少個夏夜苫耸,村子里偶爾會停電州邢,受不住熱天的我,熱的滿頭大汗被蚊子叮醒褪子,然后每次媽媽發(fā)現(xiàn)后她...
    賭w閱讀 201評論 1 2