Improve codes (#1630)

Improve codes

Reviewed-on: https://gitea.com/xorm/xorm/pulls/1630
This commit is contained in:
Lunny Xiao 2020-03-26 13:24:11 +00:00
parent b78418daa5
commit 78bb4c711d
5 changed files with 75 additions and 74 deletions

View File

@ -232,9 +232,7 @@ func (engine *Engine) Dialect() dialects.Dialect {
// NewSession New a session // NewSession New a session
func (engine *Engine) NewSession() *Session { func (engine *Engine) NewSession() *Session {
session := &Session{engine: engine} return newSession(engine)
session.Init()
return session
} }
// Close the engine // Close the engine

View File

@ -9,6 +9,8 @@ import (
) )
var ( var (
// ErrPtrSliceType represents a type error
ErrPtrSliceType = errors.New("A point to a slice is needed")
// ErrParamsType params error // ErrParamsType params error
ErrParamsType = errors.New("Params type error") ErrParamsType = errors.New("Params type error")
// ErrTableNotFound table not found error // ErrTableNotFound table not found error

View File

@ -47,24 +47,24 @@ func (e ErrFieldIsNotValid) Error() string {
return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName) return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
} }
type sessionType int type sessionType bool
const ( const (
engineSession sessionType = iota engineSession sessionType = false
groupSession groupSession sessionType = true
) )
// Session keep a pointer to sql.DB and provides all execution of all // Session keep a pointer to sql.DB and provides all execution of all
// kind of database operations. // kind of database operations.
type Session struct { type Session struct {
db *core.DB
engine *Engine engine *Engine
tx *core.Tx tx *core.Tx
statement *statements.Statement statement *statements.Statement
isAutoCommit bool isAutoCommit bool
isCommitedOrRollbacked bool isCommitedOrRollbacked bool
isAutoClose bool isAutoClose bool
isClosed bool
prepareStmt bool
// Automatically reset the statement after operations that execute a SQL // Automatically reset the statement after operations that execute a SQL
// query such as Count(), Find(), Get(), ... // query such as Count(), Find(), Get(), ...
autoResetStatement bool autoResetStatement bool
@ -77,26 +77,17 @@ type Session struct {
beforeClosures []func(interface{}) beforeClosures []func(interface{})
afterClosures []func(interface{}) afterClosures []func(interface{})
afterProcessors []executedProcessor afterProcessors []executedProcessor
prepareStmt bool
stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr)) stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr))
lastSQL string lastSQL string
lastSQLArgs []interface{} lastSQLArgs []interface{}
showSQL bool
ctx context.Context ctx context.Context
sessionType sessionType sessionType sessionType
} }
// Clone copy all the session's content and return a new session
func (session *Session) Clone() *Session {
var sess = *session
return &sess
}
func newSessionID() string { func newSessionID() string {
hash := sha256.New() hash := sha256.New()
_, err := io.CopyN(hash, rand.Reader, 50) _, err := io.CopyN(hash, rand.Reader, 50)
@ -108,63 +99,77 @@ func newSessionID() string {
return mdStr[0:20] return mdStr[0:20]
} }
// Init reset the session as the init status. func newSession(engine *Engine) *Session {
func (session *Session) Init() { var ctx context.Context
session.statement = statements.NewStatement( if engine.logSessionID {
session.engine.dialect, ctx = context.WithValue(engine.defaultContext, log.SessionIDKey, newSessionID())
session.engine.tagParser,
session.engine.DatabaseTZ,
)
session.db = session.engine.db
session.isAutoCommit = true
session.isCommitedOrRollbacked = false
session.isAutoClose = false
session.autoResetStatement = true
session.prepareStmt = false
// !nashtsai! is lazy init better?
session.afterInsertBeans = make(map[interface{}]*[]func(interface{}), 0)
session.afterUpdateBeans = make(map[interface{}]*[]func(interface{}), 0)
session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0)
session.beforeClosures = make([]func(interface{}), 0)
session.afterClosures = make([]func(interface{}), 0)
session.stmtCache = make(map[uint32]*core.Stmt)
session.afterProcessors = make([]executedProcessor, 0)
session.lastSQL = ""
session.lastSQLArgs = []interface{}{}
if session.engine.logSessionID {
session.ctx = context.WithValue(session.engine.defaultContext, log.SessionIDKey, newSessionID())
} else { } else {
session.ctx = session.engine.defaultContext ctx = engine.defaultContext
}
return &Session{
ctx: ctx,
engine: engine,
tx: nil,
statement: statements.NewStatement(
engine.dialect,
engine.tagParser,
engine.DatabaseTZ,
),
isClosed: false,
isAutoCommit: true,
isCommitedOrRollbacked: false,
isAutoClose: false,
autoResetStatement: true,
prepareStmt: false,
afterInsertBeans: make(map[interface{}]*[]func(interface{}), 0),
afterUpdateBeans: make(map[interface{}]*[]func(interface{}), 0),
afterDeleteBeans: make(map[interface{}]*[]func(interface{}), 0),
beforeClosures: make([]func(interface{}), 0),
afterClosures: make([]func(interface{}), 0),
afterProcessors: make([]executedProcessor, 0),
stmtCache: make(map[uint32]*core.Stmt),
lastSQL: "",
lastSQLArgs: make([]interface{}, 0),
sessionType: engineSession,
} }
} }
// Close release the connection from pool // Close release the connection from pool
func (session *Session) Close() { func (session *Session) Close() error {
for _, v := range session.stmtCache { for _, v := range session.stmtCache {
v.Close() if err := v.Close(); err != nil {
return err
}
} }
if session.db != nil { if !session.isClosed {
// When Close be called, if session is a transaction and do not call // When Close be called, if session is a transaction and do not call
// Commit or Rollback, then call Rollback. // Commit or Rollback, then call Rollback.
if session.tx != nil && !session.isCommitedOrRollbacked { if session.tx != nil && !session.isCommitedOrRollbacked {
session.Rollback() if err := session.Rollback(); err != nil {
return err
}
} }
session.tx = nil session.tx = nil
session.stmtCache = nil session.stmtCache = nil
session.db = nil session.isClosed = true
} }
return nil
}
func (session *Session) db() *core.DB {
return session.engine.db
} }
func (session *Session) getQueryer() core.Queryer { func (session *Session) getQueryer() core.Queryer {
if session.tx != nil { if session.tx != nil {
return session.tx return session.tx
} }
return session.db return session.db()
} }
// ContextCache enable context cache or not // ContextCache enable context cache or not
@ -175,7 +180,7 @@ func (session *Session) ContextCache(context contexts.ContextCache) *Session {
// IsClosed returns if session is closed // IsClosed returns if session is closed
func (session *Session) IsClosed() bool { func (session *Session) IsClosed() bool {
return session.db == nil return session.isClosed
} }
func (session *Session) resetStatement() { func (session *Session) resetStatement() {
@ -320,11 +325,7 @@ func (session *Session) Having(conditions string) *Session {
// DB db return the wrapper of sql.DB // DB db return the wrapper of sql.DB
func (session *Session) DB() *core.DB { func (session *Session) DB() *core.DB {
if session.db == nil { return session.db()
session.db = session.engine.DB()
session.stmtCache = make(map[uint32]*core.Stmt, 0)
}
return session.db
} }
func cleanupProcessorsClosures(slices *[]func(interface{})) { func cleanupProcessorsClosures(slices *[]func(interface{})) {

View File

@ -242,7 +242,7 @@ func (session *Session) nocacheGet(beanKind reflect.Kind, table *schemas.Table,
if err != nil { if err != nil {
return false, err return false, err
} }
// close it before covert data // close it before convert data
rows.Close() rows.Close()
dataStruct := utils.ReflectValue(bean) dataStruct := utils.ReflectValue(bean)

View File

@ -112,13 +112,14 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
return 0, ErrTableNotFound return 0, ErrTableNotFound
} }
table := session.statement.RefTable var (
size := sliceValue.Len() table = session.statement.RefTable
size = sliceValue.Len()
var colNames []string colNames []string
var colMultiPlaces []string colMultiPlaces []string
var args []interface{} args []interface{}
var cols []*schemas.Column cols []*schemas.Column
)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
v := sliceValue.Index(i) v := sliceValue.Index(i)
@ -265,12 +266,11 @@ func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
if sliceValue.Kind() != reflect.Slice { if sliceValue.Kind() != reflect.Slice {
return 0, ErrParamsType return 0, ErrPtrSliceType
} }
if sliceValue.Len() <= 0 { if sliceValue.Len() <= 0 {
return 0, nil return 0, ErrNoElementsOnSlice
} }
return session.innerInsertMulti(rowsSlicePtr) return session.innerInsertMulti(rowsSlicePtr)
@ -483,7 +483,7 @@ func (session *Session) cacheInsert(table string) error {
if cacher == nil { if cacher == nil {
return nil return nil
} }
session.engine.logger.Debugf("[cache] clear sql: %v", table) session.engine.logger.Debugf("[cache] clear SQL: %v", table)
cacher.ClearIds(table) cacher.ClearIds(table)
return nil return nil
} }