add cache for string

This commit is contained in:
Lunny Xiao 2014-11-07 17:56:33 +08:00
parent 0903741bc2
commit d9efbdccd7
3 changed files with 99 additions and 79 deletions

View File

@ -45,6 +45,10 @@ Drivers for Go's sql package which currently support database/sql includes:
# Changelog # Changelog
* **v0.4.1**
Features:
* Add deleted xorm tag for soft delete and add unscoped
* **v0.4.0 RC1** * **v0.4.0 RC1**
Changes: Changes:
* moved xorm cmd to [github.com/go-xorm/cmd](github.com/go-xorm/cmd) * moved xorm cmd to [github.com/go-xorm/cmd](github.com/go-xorm/cmd)
@ -63,7 +67,7 @@ Drivers for Go's sql package which currently support database/sql includes:
If you have [gopm](https://github.com/gpmgo/gopm) installed, If you have [gopm](https://github.com/gpmgo/gopm) installed,
gopm get github.com/go-xorm/xorm gopm get github.com/go-xorm/xorm
Or Or
go get github.com/go-xorm/xorm go get github.com/go-xorm/xorm

View File

@ -188,9 +188,9 @@ func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) {
if engine.ShowSQL { if engine.ShowSQL {
engine.overrideLogLevel(core.LOG_INFO) engine.overrideLogLevel(core.LOG_INFO)
if len(sqlArgs) > 0 { if len(sqlArgs) > 0 {
engine.Logger.Info(fmt.Sprintf("[sql] %v [args] %v", sqlStr, sqlArgs)) engine.Logger.Infof("[sql] %v [args] %v", sqlStr, sqlArgs)
} else { } else {
engine.Logger.Info(fmt.Sprintf("[sql] %v", sqlStr)) engine.Logger.Infof("[sql] %v", sqlStr)
} }
} }
} }

View File

@ -602,18 +602,35 @@ func (session *Session) DropTable(bean interface{}) error {
return err return err
} }
func (statement *Statement) JoinColumns(cols []*core.Column) string {
var colnames = make([]string, len(cols))
for i, col := range cols {
colnames[i] = statement.Engine.Quote(statement.TableName()) +
"." + statement.Engine.Quote(col.Name)
}
return strings.Join(colnames, ", ")
}
func (statement *Statement) convertIdSql(sqlStr string) string { func (statement *Statement) convertIdSql(sqlStr string) string {
if statement.RefTable != nil { if statement.RefTable != nil {
col := statement.RefTable.PKColumns()[0] cols := statement.RefTable.PKColumns()
if col != nil { if len(cols) == 0 {
sqls := splitNNoCase(sqlStr, "from", 2) return ""
if len(sqls) != 2 {
return ""
}
newsql := fmt.Sprintf("SELECT %v.%v FROM %v", statement.Engine.Quote(statement.TableName()),
statement.Engine.Quote(col.Name), sqls[1])
return newsql
} }
// *******
// TODO: this codes should be removed after multi primary key cache be supported
if len(cols) > 1 {
return ""
}
// *******
colstrs := statement.JoinColumns(cols)
sqls := splitNNoCase(sqlStr, "from", 2)
if len(sqls) != 2 {
return ""
}
return fmt.Sprintf("SELECT %s FROM %v", colstrs, sqls[1])
} }
return "" return ""
} }
@ -636,26 +653,23 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf
session.Engine.LogDebug("[xorm:cacheGet] find sql:", newsql, args) session.Engine.LogDebug("[xorm:cacheGet] find sql:", newsql, args)
ids, err := core.GetCacheSql(cacher, tableName, newsql, args) ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
if err != nil { if err != nil {
resultsSlice, err := session.query(newsql, args...) var res core.PK = make([]interface{}, len(session.Statement.RefTable.PrimaryKeys))
rows, err := session.Db.Query(newsql, args...)
if err != nil { if err != nil {
return false, err return false, err
} }
session.Engine.LogDebug("[xorm:cacheGet] query ids:", resultsSlice) defer rows.Close()
ids = make([]core.PK, 0)
if len(resultsSlice) > 0 { if rows.Next() {
data := resultsSlice[0] err = rows.ScanSlice(&res)
var id int64 if err != nil {
if v, ok := data[session.Statement.RefTable.PrimaryKeys[0]]; !ok { return false, err
return false, ErrCacheFailed
} else {
// TODO https://github.com/go-xorm/xorm/issues/144, PK may not always be int64
id, err = strconv.ParseInt(string(v), 10, 64)
if err != nil {
return false, err
}
} }
ids = append(ids, core.PK{id}) } else {
return false, ErrCacheFailed
} }
ids = []core.PK{res}
session.Engine.LogDebug("[xorm:cacheGet] cache ids:", newsql, ids) session.Engine.LogDebug("[xorm:cacheGet] cache ids:", newsql, ids)
err = core.PutCacheSql(cacher, ids, tableName, newsql, args) err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
if err != nil { if err != nil {
@ -703,7 +717,7 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf
return false, nil return false, nil
} }
func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) { func (session *Session) cacheFind(v reflect.Value, t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) {
if session.Statement.RefTable == nil || if session.Statement.RefTable == nil ||
len(session.Statement.RefTable.PrimaryKeys) != 1 || len(session.Statement.RefTable.PrimaryKeys) != 1 ||
indexNoCase(sqlStr, "having") != -1 || indexNoCase(sqlStr, "having") != -1 ||
@ -724,33 +738,33 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
cacher := session.Engine.getCacher2(table) cacher := session.Engine.getCacher2(table)
ids, err := core.GetCacheSql(cacher, session.Statement.TableName(), newsql, args) ids, err := core.GetCacheSql(cacher, session.Statement.TableName(), newsql, args)
if err != nil { if err != nil {
//session.Engine.LogError(err) rows, err := session.Db.Query(newsql, args...)
resultsSlice, err := session.query(newsql, args...)
if err != nil { if err != nil {
return err return err
} }
// 查询数目太大,采用缓存将不是一个很好的方式〠defer rows.Close()
if len(resultsSlice) > 500 {
session.Engine.LogDebug("[xorm:cacheFind] ids length %v > 500, no cache", len(resultsSlice)) var i int
return ErrCacheFailed ids = make([]core.PK, 0)
for rows.Next() {
i++
if i > 500 {
session.Engine.LogDebug("[xorm:cacheFind] ids length > 500, no cache")
return ErrCacheFailed
}
fmt.Println("v.interface", v.Interface())
var res = session.Engine.IdOf(v.Interface())
fmt.Println("!!!!!", res)
err = rows.ScanSlice(&res)
fmt.Println("-----", res)
if err != nil {
return err
}
ids = append(ids, res)
} }
tableName := session.Statement.TableName() tableName := session.Statement.TableName()
ids = make([]core.PK, 0)
if len(resultsSlice) > 0 {
for _, data := range resultsSlice {
var id int64
if v, ok := data[session.Statement.RefTable.PrimaryKeys[0]]; !ok {
return errors.New("no id")
} else {
id, err = strconv.ParseInt(string(v), 10, 64)
if err != nil {
return err
}
}
ids = append(ids, core.PK{id})
}
}
session.Engine.LogDebug("[xorm:cacheFind] cache ids:", ids, tableName, newsql, args) session.Engine.LogDebug("[xorm:cacheFind] cache ids:", ids, tableName, newsql, args)
err = core.PutCacheSql(cacher, ids, tableName, newsql, args) err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
if err != nil { if err != nil {
@ -1057,16 +1071,17 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
sliceElementType := sliceValue.Type().Elem() sliceElementType := sliceValue.Type().Elem()
var table *core.Table var table *core.Table
var pv reflect.Value
if session.Statement.RefTable == nil { if session.Statement.RefTable == nil {
if sliceElementType.Kind() == reflect.Ptr { if sliceElementType.Kind() == reflect.Ptr {
if sliceElementType.Elem().Kind() == reflect.Struct { if sliceElementType.Elem().Kind() == reflect.Struct {
pv := reflect.New(sliceElementType.Elem()) pv = reflect.New(sliceElementType.Elem())
table = session.Engine.autoMapType(pv.Elem()) table = session.Engine.autoMapType(pv.Elem())
} else { } else {
return errors.New("slice type") return errors.New("slice type")
} }
} else if sliceElementType.Kind() == reflect.Struct { } else if sliceElementType.Kind() == reflect.Struct {
pv := reflect.New(sliceElementType) pv = reflect.New(sliceElementType)
table = session.Engine.autoMapType(pv.Elem()) table = session.Engine.autoMapType(pv.Elem())
} else { } else {
return errors.New("slice type") return errors.New("slice type")
@ -1074,8 +1089,11 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
session.Statement.RefTable = table session.Statement.RefTable = table
} else { } else {
table = session.Statement.RefTable table = session.Statement.RefTable
pv = reflect.New(sliceElementType)
} }
fmt.Println("xxxxxxx", pv.Interface())
if len(condiBean) > 0 { if len(condiBean) > 0 {
colNames, args := buildConditions(session.Engine, table, condiBean[0], true, true, colNames, args := buildConditions(session.Engine, table, condiBean[0], true, true,
false, true, session.Statement.allUseBool, session.Statement.useAllCols, false, true, session.Statement.allUseBool, session.Statement.useAllCols,
@ -1116,7 +1134,8 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
if cacher := session.Engine.getCacher2(table); cacher != nil && if cacher := session.Engine.getCacher2(table); cacher != nil &&
session.Statement.UseCache && session.Statement.UseCache &&
!session.Statement.IsDistinct { !session.Statement.IsDistinct {
err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...) fmt.Println("......", pv.Interface())
err = session.cacheFind(pv, sliceElementType, sqlStr, rowsSlicePtr, args...)
if err != ErrCacheFailed { if err != ErrCacheFailed {
return err return err
} }
@ -2136,29 +2155,29 @@ func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.T
x = x.In(time.UTC) x = x.In(time.UTC)
x = time.Date(x.Year(), x.Month(), x.Day(), x.Hour(), x = time.Date(x.Year(), x.Month(), x.Day(), x.Hour(),
x.Minute(), x.Second(), x.Nanosecond(), session.Engine.TZLocation) x.Minute(), x.Second(), x.Nanosecond(), session.Engine.TZLocation)
session.Engine.LogDebug("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) session.Engine.LogDebugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} else { } else {
session.Engine.LogDebug("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) session.Engine.LogDebugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} }
} else if len(sdata) > 19 { } else if len(sdata) > 19 {
x, err = time.ParseInLocation(time.RFC3339Nano, sdata, session.Engine.TZLocation) x, err = time.ParseInLocation(time.RFC3339Nano, sdata, session.Engine.TZLocation)
session.Engine.LogDebug("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) session.Engine.LogDebugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
if err != nil { if err != nil {
x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, session.Engine.TZLocation) x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, session.Engine.TZLocation)
session.Engine.LogDebug("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) session.Engine.LogDebugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} }
if err != nil { if err != nil {
x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, session.Engine.TZLocation) x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, session.Engine.TZLocation)
session.Engine.LogDebug("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) session.Engine.LogDebugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} }
} else if len(sdata) == 19 { } else if len(sdata) == 19 {
x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, session.Engine.TZLocation) x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, session.Engine.TZLocation)
session.Engine.LogDebug("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) session.Engine.LogDebugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' { } else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
x, err = time.ParseInLocation("2006-01-02", sdata, session.Engine.TZLocation) x, err = time.ParseInLocation("2006-01-02", sdata, session.Engine.TZLocation)
session.Engine.LogDebug("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) session.Engine.LogDebugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} else if col.SQLType.Name == core.Time { } else if col.SQLType.Name == core.Time {
if strings.Contains(sdata, " ") { if strings.Contains(sdata, " ") {
ssd := strings.Split(sdata, " ") ssd := strings.Split(sdata, " ")
@ -2172,7 +2191,7 @@ func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.T
st := fmt.Sprintf("2006-01-02 %v", sdata) st := fmt.Sprintf("2006-01-02 %v", sdata)
x, err = time.ParseInLocation("2006-01-02 15:04:05", st, session.Engine.TZLocation) x, err = time.ParseInLocation("2006-01-02 15:04:05", st, session.Engine.TZLocation)
session.Engine.LogDebug("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) session.Engine.LogDebugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} else { } else {
outErr = errors.New(fmt.Sprintf("unsupported time format %v", sdata)) outErr = errors.New(fmt.Sprintf("unsupported time format %v", sdata))
return return
@ -2922,12 +2941,13 @@ func (statement *Statement) convertUpdateSql(sqlStr string) (string, string) {
if statement.RefTable == nil || len(statement.RefTable.PrimaryKeys) != 1 { if statement.RefTable == nil || len(statement.RefTable.PrimaryKeys) != 1 {
return "", "" return "", ""
} }
colstrs := statement.JoinColumns(statement.RefTable.PKColumns())
sqls := splitNNoCase(sqlStr, "where", 2) sqls := splitNNoCase(sqlStr, "where", 2)
if len(sqls) != 2 { if len(sqls) != 2 {
if len(sqls) == 1 { if len(sqls) == 1 {
return sqls[0], fmt.Sprintf("SELECT %v FROM %v", return sqls[0], fmt.Sprintf("SELECT %v FROM %v",
statement.Engine.Quote(statement.RefTable.PrimaryKeys[0]), colstrs, statement.Engine.Quote(statement.TableName()))
statement.Engine.Quote(statement.RefTable.Name))
} }
return "", "" return "", ""
} }
@ -2954,7 +2974,7 @@ func (statement *Statement) convertUpdateSql(sqlStr string) (string, string) {
} }
return sqls[0], fmt.Sprintf("SELECT %v FROM %v WHERE %v", return sqls[0], fmt.Sprintf("SELECT %v FROM %v WHERE %v",
statement.Engine.Quote(statement.RefTable.PrimaryKeys[0]), statement.Engine.Quote(statement.TableName()), colstrs, statement.Engine.Quote(statement.TableName()),
whereStr) whereStr)
} }
@ -2974,7 +2994,7 @@ func (session *Session) cacheInsert(tables ...string) error {
return nil return nil
} }
func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error { func (session *Session) cacheUpdate(v reflect.Value, sqlStr string, args ...interface{}) error {
if session.Statement.RefTable == nil || len(session.Statement.RefTable.PrimaryKeys) != 1 { if session.Statement.RefTable == nil || len(session.Statement.RefTable.PrimaryKeys) != 1 {
return ErrCacheFailed return ErrCacheFailed
} }
@ -3003,27 +3023,23 @@ func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error {
session.Engine.LogDebug("[xorm:cacheUpdate] get cache sql", newsql, args[nStart:]) session.Engine.LogDebug("[xorm:cacheUpdate] get cache sql", newsql, args[nStart:])
ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:]) ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:])
if err != nil { if err != nil {
resultsSlice, err := session.query(newsql, args[nStart:]...) rows, err := session.Db.Query(newsql, args[nStart:]...)
if err != nil { if err != nil {
return err return err
} }
session.Engine.LogDebug("[xorm:cacheUpdate] find updated id", resultsSlice) defer rows.Close()
ids = make([]core.PK, 0) ids = make([]core.PK, 0)
if len(resultsSlice) > 0 { for rows.Next() {
for _, data := range resultsSlice { var res = session.Engine.IdOf(v.Interface())
var id int64 fmt.Println("00000000", res)
if v, ok := data[session.Statement.RefTable.PrimaryKeys[0]]; !ok { err = rows.ScanSlice(&res)
return errors.New("no id") if err != nil {
} else { return err
id, err = strconv.ParseInt(string(v), 10, 64)
if err != nil {
return err
}
}
ids = append(ids, core.PK{id})
} }
ids = append(ids, res)
} }
session.Engine.LogDebug("[xorm:cacheUpdate] find updated id", ids)
} /*else { } /*else {
session.Engine.LogDebug("[xorm:cacheUpdate] del cached sql:", tableName, newsql, args) session.Engine.LogDebug("[xorm:cacheUpdate] del cached sql:", tableName, newsql, args)
cacher.DelIds(tableName, genSqlKey(newsql, args)) cacher.DelIds(tableName, genSqlKey(newsql, args))
@ -3403,7 +3419,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
} }
sqlStr, sqlStrForCache := "", "" sqlStr, sqlStrForCache := "", ""
argsForCache := make([]interface{}, 0, len(args) * 2) argsForCache := make([]interface{}, 0, len(args)*2)
if session.Statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled if session.Statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled
sqlStr = fmt.Sprintf("DELETE FROM %v WHERE %v", sqlStr = fmt.Sprintf("DELETE FROM %v WHERE %v",
session.Engine.Quote(session.Statement.TableName()), condition) session.Engine.Quote(session.Statement.TableName()), condition)