版本
golang -- 1.12.4
mongodb -- 4.0
go driver -- 1.0.0簡介
mongodb的數(shù)據(jù)庫driver在官方文檔里面明確寫明所有的數(shù)據(jù)庫連接需要自己建立和釋放,而且建議盡量復(fù)用已有的建立瘤泪,那么也就是說driver里面并未實現(xiàn)連接池的功能灶泵。在我們實際應(yīng)用中就需要自己實現(xiàn)這套數(shù)據(jù)庫連接池提升程序和數(shù)據(jù)庫之間的執(zhí)行效率。
- 設(shè)計思路
用一個數(shù)組來存放數(shù)據(jù)庫連接的指針对途,并記錄每一個指針兩個狀態(tài): a.是否申請了數(shù)據(jù)庫連接 b.這個連接是否已經(jīng)給系統(tǒng)在使用中赦邻。舉個例子就比較好理解了:
-
申請一個用于存放數(shù)據(jù)連接的數(shù)組,一開始空的什么都沒有
pool_initial.png -
程序需要一個數(shù)據(jù)庫連接实檀,連接池把數(shù)組第一個位置建立一個數(shù)據(jù)庫連接惶洲,并把這個連接的狀態(tài)置為:a.已申請 b.已給系統(tǒng)
pool_create_connection.png -
程序使用完釋放數(shù)據(jù)庫連接按声,現(xiàn)在數(shù)據(jù)庫指針狀態(tài)為:a.已申請 b.未使用
pool_release_connection.png 程序需要新申請一個數(shù)據(jù)庫連接,那么就回到了第2的狀態(tài)湃鹊。
- 核心代碼
const(
MAX_CONNECTION = 10
INITIAL_CONNECTION = 4
AVAILABLE = false
USED = true
)
/*
代碼取了一個巧儒喊,用實際存放數(shù)據(jù)庫指針的大小ClientPool.size和mongodata.flag來表示上述a镣奋,b兩個狀態(tài)
如果mongodata.flag都為USED币呵,那么需要新申請個數(shù)據(jù)庫連接: size++
clientList: the client pool
clientAvailable: the available flag, means the location and available flag in the client pool
size: the size of allocated client pool <= MAX_CONNECTION
*/
type mongodata struct{
client *mongo.Client
pos int
flag bool
}
type ClientPool struct{
clientList [MAX_CONNECTION]mongodata
size int
}
//create a new database connection to the pool
func (cp *ClientPool) allocateCToPool(pos int) (err error){
cp.clientList[pos].client, err = Dbconnect()
if err != nil {
utils.Logger.SetPrefix("WARNING ")
utils.Logger.Println("allocateCToPool - allocateCToPool failed,position: ", pos, err)
return err
}
cp.clientList[pos].flag = USED
cp.clientList[pos].pos = pos
return nil
}
//apply a connection from the pool
func (cp *ClientPool) getCToPool(pos int){
cp.clientList[pos].flag = USED
}
//free a connection back to the pool
func (cp *ClientPool) putCBackPool(pos int){
cp.clientList[pos].flag = AVAILABLE
}
//program apply a database connection
func GetClient() (mongoclient *mongodata, err error) {
for i:=1; i<cp.size; i++ {
if cp.clientList[i].flag == AVAILABLE{
return &cp.clientList[i], nil
}
}
if cp.size < MAX_CONNECTION{
err = cp.allocateCToPool(cp.size)
if err != nil {
utils.Logger.SetPrefix("WARNING ")
utils.Logger.Println("GetClient - DB pooling allocate failed", err)
return nil, err
}
pos := cp.size
cp.size++
return &cp.clientList[pos], nil
} else {
utils.Logger.SetPrefix("WARNING ")
utils.Logger.Println("GetClient - DB pooling is fulled")
return nil, errors.New("DB pooling is fulled")
}
}
//program release a connection
func ReleaseClient(mongoclient *mongodata){
cp.putCBackPool(mongoclient.pos)
}
以上就是核心代碼實現(xiàn),但是這個代碼有一個問題侨颈,就是在高并發(fā)下并非協(xié)程安全余赢,這個留在下一篇《用golang實現(xiàn)mongodb數(shù)據(jù)庫連接池-高級篇-協(xié)程安全》來優(yōu)化。