diff --git a/engine.go b/engine.go index 59f3ecb4..0645ac35 100644 --- a/engine.go +++ b/engine.go @@ -115,77 +115,104 @@ func (engine *Engine) LogError(contents ...interface{}) { func (engine *Engine) Sql(querystring string, args ...interface{}) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.Sql(querystring, args...) } func (engine *Engine) Cascade(trueOrFalse ...bool) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.Cascade(trueOrFalse...) } func (engine *Engine) Where(querystring string, args ...interface{}) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.Where(querystring, args...) } func (engine *Engine) Id(id int64) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.Id(id) } func (engine *Engine) Charset(charset string) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.Charset(charset) } func (engine *Engine) StoreEngine(storeEngine string) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.StoreEngine(storeEngine) } func (engine *Engine) Cols(columns ...string) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.Cols(columns...) } func (engine *Engine) Trans(t string) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.Trans(t) } func (engine *Engine) In(column string, args ...interface{}) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.In(column, args...) } func (engine *Engine) Table(tableNameOrBean interface{}) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.Table(tableNameOrBean) } func (engine *Engine) Limit(limit int, start ...int) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.Limit(limit, start...) } +func (engine *Engine) Desc(colName string) *Session { + session := engine.NewSession() + session.IsAutoClose = true + return session.Desc(colName) +} + +func (engine *Engine) Asc(colName string) *Session { + session := engine.NewSession() + session.IsAutoClose = true + return session.Asc(colName) +} + func (engine *Engine) OrderBy(order string) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.OrderBy(order) } //The join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN func (engine *Engine) Join(join_operator, tablename, condition string) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.Join(join_operator, tablename, condition) } func (engine *Engine) GroupBy(keys string) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.GroupBy(keys) } func (engine *Engine) Having(conditions string) *Session { session := engine.NewSession() + session.IsAutoClose = true return session.Having(conditions) } diff --git a/examples/maxconnect.go b/examples/maxconnect.go index 636d531e..bb979298 100644 --- a/examples/maxconnect.go +++ b/examples/maxconnect.go @@ -8,6 +8,7 @@ import ( "os" //"time" //"sync/atomic" + "runtime" xorm "xorm" ) @@ -34,7 +35,8 @@ func test(engine *xorm.Engine) { return } - engine.Pool.SetMaxConns(50) + engine.ShowSQL = true + engine.Pool.SetMaxConns(5) size := 1000 queue := make(chan int, size) @@ -79,12 +81,11 @@ func test(engine *xorm.Engine) { <-queue } - //conns := atomic.LoadInt32(&xorm.ConnectionNum) - //fmt.Println("connection number:", conns) fmt.Println("end") } func main() { + runtime.GOMAXPROCS(2) fmt.Println("create engine") engine, err := sqliteEngine() if err != nil { diff --git a/pool.go b/pool.go index 3dc74329..21bda9af 100644 --- a/pool.go +++ b/pool.go @@ -2,7 +2,7 @@ package xorm import ( "database/sql" - //"fmt" + "fmt" "sync" //"sync/atomic" "time" @@ -108,30 +108,36 @@ func (s *SysConnectPool) Init(engine *Engine) error { // RetrieveDB just return the only db func (p *SysConnectPool) RetrieveDB(engine *Engine) (db *sql.DB, err error) { - if p.maxConns != -1 { - p.cond.L.Lock() - //fmt.Println("before retrieve - current connections:", p.curConns, p.maxConns) - for p.curConns >= p.maxConns-1 { - //fmt.Println("waiting...") + if p.maxConns > 0 { + p.condMutex.Lock() + fmt.Println("before retrieve - current connections:", p.curConns, p.maxConns) + for p.curConns >= p.maxConns { + fmt.Println("waiting...", p.curConns) p.cond.Wait() } + //p.mutex.Lock() p.curConns += 1 - p.cond.L.Unlock() + p.cond.Signal() + //p.mutex.Lock() + p.condMutex.Unlock() } return p.db, nil } // ReleaseDB do nothing func (p *SysConnectPool) ReleaseDB(engine *Engine, db *sql.DB) { - if p.maxConns != -1 { - p.cond.L.Lock() - //fmt.Println("before release - current connections:", p.curConns, p.maxConns) + if p.maxConns > 0 { + p.condMutex.Lock() + fmt.Println("before release - current connections:", p.curConns, p.maxConns) //if p.curConns >= p.maxConns-2 { - //fmt.Println("signaling...") + fmt.Println("signaling...") + //p.mutex.Lock() + p.curConns -= 1 + //p.mutex.Unlock() p.cond.Signal() //} - p.curConns -= 1 - p.cond.L.Unlock() + p.condMutex.Unlock() + } } diff --git a/session.go b/session.go index 7162f8ac..bfc1798b 100644 --- a/session.go +++ b/session.go @@ -18,6 +18,7 @@ type Session struct { IsAutoCommit bool IsCommitedOrRollbacked bool TransType string + IsAutoClose bool } func (session *Session) Init() { @@ -25,6 +26,7 @@ func (session *Session) Init() { session.Statement.Init() session.IsAutoCommit = true session.IsCommitedOrRollbacked = false + session.IsAutoClose = false } func (session *Session) Close() { @@ -33,7 +35,7 @@ func (session *Session) Close() { session.Engine.Pool.ReleaseDB(session.Engine, session.Db) session.Db = nil session.Tx = nil - session.Init() + //session.Init() } }() } @@ -83,6 +85,22 @@ func (session *Session) OrderBy(order string) *Session { return session } +func (session *Session) Desc(colName string) *Session { + if session.Statement.OrderStr != "" { + session.Statement.OrderStr += ", " + } + session.Statement.OrderStr += colName + " desc" + return session +} + +func (session *Session) Asc(colName string) *Session { + if session.Statement.OrderStr != "" { + session.Statement.OrderStr += ", " + } + session.Statement.OrderStr += colName + " asc" + return session +} + func (session *Session) StoreEngine(storeEngine string) *Session { session.Statement.StoreEngine = storeEngine return session @@ -384,6 +402,10 @@ func (session *Session) CreateAll() error { return err } + if session.IsAutoClose { + defer session.Close() + } + for _, table := range session.Engine.Tables { session.Statement.RefTable = table err := session.createOneTable() @@ -400,6 +422,10 @@ func (session *Session) DropTable(bean interface{}) error { return err } + if session.IsAutoClose { + defer session.Close() + } + t := reflect.Indirect(reflect.ValueOf(bean)).Type() defer session.Statement.Init() if t.Kind() == reflect.String { @@ -421,6 +447,10 @@ func (session *Session) Get(bean interface{}) (bool, error) { return false, err } + if session.IsAutoClose { + defer session.Close() + } + defer session.Statement.Init() session.Statement.Limit(1) var sql string @@ -458,6 +488,10 @@ func (session *Session) Count(bean interface{}) (int64, error) { return 0, err } + if session.IsAutoClose { + defer session.Close() + } + defer session.Statement.Init() var sql string var args []interface{} @@ -491,6 +525,10 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) return err } + if session.IsAutoClose { + defer session.Close() + } + defer session.Statement.Init() sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map { @@ -558,6 +596,10 @@ func (session *Session) Ping() error { return err } + if session.IsAutoClose { + defer session.Close() + } + return session.Db.Ping() } @@ -567,6 +609,10 @@ func (session *Session) DropAll() error { return err } + if session.IsAutoClose { + defer session.Close() + } + for _, table := range session.Engine.Tables { session.Statement.Init() session.Statement.RefTable = table @@ -585,6 +631,10 @@ func (session *Session) Query(sql string, paramStr ...interface{}) (resultsSlice return nil, err } + if session.IsAutoClose { + defer session.Close() + } + for _, filter := range session.Engine.Filters { sql = filter.Do(sql, session) } @@ -669,12 +719,16 @@ func (session *Session) Insert(beans ...interface{}) (int64, error) { if !isInTransaction { err = session.Begin() - defer session.Close() + //defer session.Close() if err != nil { return 0, err } } + if session.IsAutoClose { + defer session.Close() + } + for _, bean := range beans { sliceValue := reflect.Indirect(reflect.ValueOf(bean)) if sliceValue.Kind() == reflect.Slice { @@ -819,9 +873,10 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) { err := session.newDb() - if session.IsAutoCommit { + if session.IsAutoClose { defer session.Close() } + if err != nil { return 0, err } @@ -948,7 +1003,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { func (session *Session) InsertOne(bean interface{}) (int64, error) { err := session.newDb() - if session.IsAutoCommit { + if session.IsAutoClose { defer session.Close() } if err != nil { @@ -960,7 +1015,7 @@ func (session *Session) InsertOne(bean interface{}) (int64, error) { func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) { err := session.newDb() - if session.IsAutoCommit { + if session.IsAutoClose { defer session.Close() } if err != nil { @@ -1038,7 +1093,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 func (session *Session) Delete(bean interface{}) (int64, error) { err := session.newDb() - if session.IsAutoCommit { + if session.IsAutoClose { defer session.Close() } if err != nil {