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