測並發時由於使用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 }