自营连接池工具

刚刚开始写连接池时的一些想法:
1、连接池最重要的是在于空闲、忙碌和峰值时连接的操作逻辑;
2、连接池工具跟MysqL、redis、tcp、没有什么特定的关系,只要生产模式是io.Closer接口即可;
3、连接池多数情况下在连接使用释放后会进行Rollback,这里的操作是直接进行Close操作(多数操作是直接进行连接回池复用),但是我这儿考虑到可能服务连接受网络波动,所以干脆进行Close?
4、有一个单独的协程不断的在监控连接池中的chan io.Closer不断进行连接补充、状态变化(如空闲、忙碌切换)

不多废话上pool.go代码

package core

import (
    "errors"
    "time"
    "sync"
    "io"
    "fmt"
)

//连接池生产
type PoolFactory func() (io.Closer,error)

//连接池管理实例
type Pool struct {
    mu      sync.Mutex

    MaxIdle int
    MaxOpen int
    IsDebug bool
    Name    string

    busy    bool
    factory PoolFactory
    stack   chan io.Closer
}

//new MysqLPool
func NewPool(factory PoolFactory,maxIdle int,maxOpen int,name string) *Pool {
    pool := new(Pool)
    pool.Name = name
    pool.factory = factory
    pool.setinit(maxIdle,maxOpen)
    return pool
}

//log
func (this *Pool)log(value ...interface{}) {
    if this.IsDebug {
        fmt.Println("[pool]",this.Name,value)
    }
}

//set init
func (this *Pool)setinit(maxIdle int,maxOpen int) error {
    if maxOpen < maxIdle {
        return errors.New("maxOpen can not less than maxIdle")
    }

    this.stack = make(chan io.Closer,maxOpen)
    go func() {
        for {
            busyState := this.busy && len(this.stack) < maxOpen
            idleState := len(this.stack) < maxIdle
            if maxIdle <= 0 || busyState || idleState {
                one,err := this.factory()
                if err == nil {
                    this.stack <- one
                }
                this.log("create one",len(this.stack))
            }
            time.Sleep(time.Microsecond * 10)
        }
    }()
    return nil
}


//back to pool
func (this *Pool)Back(one io.Closer) error {
    if one != nil {
        return one.Close()
    }
    return errors.New("back instance is nil")
}

//get instance
func (this *Pool)Get() (io.Closer,error) {
    this.mu.Lock()
    defer this.mu.Unlock()

    if this.MaxIdle > 0 && len(this.stack) < this.MaxIdle {
        this.busy = true
    } else {
        this.busy = false
    }

    select {
    case one := <-this.stack:
        this.log("use one")
        return one,nil
    case <-time.After(time.Microsecond * 10):
        this.busy = true
        return nil,errors.New("pool timeout")
    }
}

如何使用连接池呢?灰常简单
这里使用了gorm来创建MysqL连接的方式进行facotry pool工厂创建

package main

import (
    _ "github.com/go-sql-driver/MysqL"
    "io"
    "core"
)

var pool *core.Pool
function main(){
    pool = core.NewPool(poolMysqLFactory,5,50,"MysqL")
    pool.IsDebug = true
    //use pool
    err,conn := pool.Get()
    //balabala use conn
    conn.Close()
    time.Sleep(time.Hour*1)
}

//MysqL pool factory
func poolMysqLFactory() (io.Closer,error) {
    conn,err := gorm.Open("MysqL","username:password@tcp(localhost:3306)/test?charset=utf8&parseTime=True&loc=Local")
    if err != nil {
        return nil,err
    }
    return conn,nil
}

相关文章

1、Golang指针 在介绍Golang指针隐式间接引用前,先简单说下...
1、概述 1.1&#160;Protocol buffers定义 Protocol buffe...
判断文件是否存在,需要用到"os"包中的两个函数: os.Stat(...
1、编译环境 OS :Loongnix-Server Linux release 8.3 CPU指...
1、概述 Golang是一种强类型语言,虽然在代码中经常看到i:=1...
1、概述 在《Golang常用语法糖》这篇博文中我们讲解Golang中...