go 自己封的postgresql连接池操作包

测并发时由于使用db时没有lock,当连接数超过postgres设定的最大值时报错too many clients,于是问了下老师,老师说用连接池,一开始打开固定个数的db,每次都用这些db,而且每个db用的时候要加锁

于是就开始想如何用lock来实现每次让进来的数据库请求排队,每次分配一个空闲的db给队列中第一个请求,但想了好久发现用锁处理起来好复杂,无法确定哪些db是空闲的,又改如何让请求排队

后来实在想不出来,换了个思路,能不能用go的特性channal实现,猛然发现可以一开始将固定个数的db塞到channal,每次请求出队一个可用的db,用完后又将db返回channal,而且channal自带锁的功能,当channal为空时(没有db可用)请求会等待,形成了自然队列,前面的所有问题都解决了

package myDB

import (
    "database/sql"
    "errors"

    _ "github.com/lib/pq"
)

//var db *sql.DB = nil
//
//func OpenSql() error {
//  var err error = nil
//  db, err = sql.Open("postgres", "port=5432 user=postgres password=123456 dbname=postgres sslmode=disable")
//  return err
//}
//
//func GetDB() (*sql.DB, error) {
//  if db == nil {
//      return nil, errors.New("db hadn't open")
//  }
//  return db, nil
//}

var dbQueue chan *sql.DB

func Init(queue chan *sql.DB) {
    dbQueue = queue
}
func open() *sql.DB {
    return <-dbQueue
}
func close(db *sql.DB) {
    dbQueue <- db
}

func dealResult(result sql.Result) error {
    affect, err := result.RowsAffected()
    if err != nil {
        return err
    }
    if affect <= 0 {
        return errors.New("DBExec no affect")
    }
    return nil
}
func ExecSql(Sql string, args ...interface{}) error {
    db := open()
    defer close(db)
    stmt, err := db.Prepare(Sql)
    if err != nil {
        return err
    }
    defer stmt.Close()
    result, err := stmt.Exec(args...)
    if err != nil {
        return err
    }
    return dealResult(result)
}

func QuerySql(Sql string, args ...interface{}) (*sql.Rows, error) {
    db := open()
    defer close(db)
    stmt, err := db.Prepare(Sql)
    if err != nil {
        return nil, err
    }
    defer stmt.Close()
    rows, err := stmt.Query(args...)
    if err != nil {
        return nil, err
    }
    return rows, err
}

func TxQuerySql(tx *sql.Tx, Sql string, args ...interface{}) (*sql.Stmt, *sql.Rows, error) {
    stmt, err := tx.Prepare(Sql)
    if err != nil {
        return nil, nil, err
    }
    rows, err := stmt.Query(args...)
    if err != nil {
        return nil, nil, err
    }
    return stmt, rows, err
}

func TxExecSql(tx *sql.Tx, Sql string, args ...interface{}) error {
    stmt, err := tx.Prepare(Sql)
    if err != nil {
        return err
    }
    defer stmt.Close()
    result, err := stmt.Exec(args...)
    if err != nil {
        return err
    }
    return dealResult(result)
}

func ExecMultiSql(Sql string, member []string, args ...interface{}) error {
    db := open()
    defer close(db)
    stmt, err := db.Prepare(Sql)
    if err != nil {
        return err
    }
    defer stmt.Close()
    for _, val := range member {
        allArgs := make([]interface{}, 0)
        allArgs = append(allArgs, val)
        allArgs = append(allArgs, args...)
        result, err := stmt.Exec(allArgs...)
        if err != nil {
            return err
        }
        err = dealResult(result)
        if err != nil {
            return err
        }
    }
    return nil
}

func TxExecMultiSql(tx *sql.Tx, Sql string, member []string, args ...interface{}) error {
    stmt, err := tx.Prepare(Sql)
    if err != nil {
        return err
    }
    defer stmt.Close()
    for _, val := range member {
        allArgs := make([]interface{}, 0)
        allArgs = append(allArgs, val)
        allArgs = append(allArgs, args...)
        result, err := stmt.Exec(allArgs...)
        if err != nil {
            return err
        }
        err = dealResult(result)
        if err != nil {
            return err
        }
    }
    return nil
}