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 }