自营连接池工具

前端之家收集整理的这篇文章主要介绍了自营连接池工具前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

刚刚开始写连接池时的一些想法:
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
}

猜你在找的Go相关文章