diff --git a/QuickStart.md b/QuickStart.md index b2c6cfc5..99dbe3d8 100644 --- a/QuickStart.md +++ b/QuickStart.md @@ -170,6 +170,14 @@ type User struct { - 3.支持`type MyString string`等自定义的field,支持Slice, Map等field成员,这些成员默认存储为Text类型,并且默认将使用Json格式来序列化和反序列化。也支持数据库字段类型为Blob类型,如果是Blob类型,则先使用Jsong格式序列化再转成[]byte格式。当然[]byte或者[]uint8默认为Blob类型并且都已二进制方式存储。 +- 4.实现了Conversion接口的类型或者结构体,将根据接口的转换方式在类型和数据库记录之间进行相互转换。 +```Go +type Conversion interface { + FromDB([]byte) error + ToDB() ([]byte, error) +} +``` + ## 3.创建表 diff --git a/README_CN.md b/README_CN.md index 5b95d0bc..601de2f3 100644 --- a/README_CN.md +++ b/README_CN.md @@ -7,6 +7,7 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作 [![Build Status](https://drone.io/github.com/lunny/xorm/status.png)](https://drone.io/github.com/lunny/xorm/latest) ## 讨论 + 请加入QQ群:280360085 进行讨论。 ## 驱动支持 @@ -48,21 +49,22 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作 * 支持数据库连接池 -* 支持级联加载struct +* 支持级联加载struct ## 安装 go get github.com/lunny/xorm -## 快速开始 - -请访问 [快速开始](https://github.com/lunny/xorm/blob/master/QuickStart.md) 查看详细文档 - - ## 文档 + +* [快速开始](https://github.com/lunny/xorm/blob/master/QuickStart.md) -请访问 [GoWalker](http://gowalker.org/github.com/lunny/xorm) 查看详细文档 +* [GoWalker代码文档](http://gowalker.org/github.com/lunny/xorm) + +## 案例 + +* [Godaily.org](http://godaily.org) ## FAQ @@ -75,6 +77,8 @@ type User struct { Name string `json:"name" xorm:"name"` } ``` +2.问:xorm有几种命名映射规则? +答案:目前支持SnakeMapper和SameMapper两种。SnakeMapper支持结构体和成员以驼峰式命名而数据库表和字段以下划线连接命名;SameMapper支持结构体和数据库的命名保持一致的映射。 ## LICENSE diff --git a/cache.go b/cache.go index e363236c..53194841 100644 --- a/cache.go +++ b/cache.go @@ -18,7 +18,7 @@ type CacheStore interface { type MemoryStore struct { store map[interface{}]interface{} - mutex sync.Mutex + mutex sync.RWMutex } func NewMemoryStore() *MemoryStore { @@ -34,8 +34,8 @@ func (s *MemoryStore) Put(key, value interface{}) error { } func (s *MemoryStore) Get(key interface{}) (interface{}, error) { - s.mutex.Lock() - defer s.mutex.Unlock() + s.mutex.Rlock() + defer s.mutex.UnRlock() //fmt.Println("before get store:", s.store) if v, ok := s.store[key]; ok { return v, nil diff --git a/session.go b/session.go index 0d6e7e2e..85226d48 100644 --- a/session.go +++ b/session.go @@ -392,13 +392,14 @@ func (session *Session) cacheGet(bean interface{}, sql string, args ...interface cacher := session.Statement.RefTable.Cacher tableName := session.Statement.TableName() + session.Engine.LogDebug("[xorm:cacheGet] find sql:", newsql, args) ids, err := getCacheSql(cacher, tableName, newsql, args) if err != nil { resultsSlice, err := session.query(newsql, args...) if err != nil { return false, err } - + session.Engine.LogDebug("[xorm:cacheGet] query ids:", resultsSlice) ids = make([]int64, 0) if len(resultsSlice) > 0 { data := resultsSlice[0] @@ -413,19 +414,19 @@ func (session *Session) cacheGet(bean interface{}, sql string, args ...interface } ids = append(ids, id) } - session.Engine.LogDebug("[xorm:cache] cache ids:", newsql, ids) + session.Engine.LogDebug("[xorm:cacheGet] cache ids:", newsql, ids) err = putCacheSql(cacher, ids, tableName, newsql, args) if err != nil { return false, err } } else { - session.Engine.LogDebug("[xorm:cache] cached sql:", newsql) + session.Engine.LogDebug("[xorm:cacheGet] cached sql:", newsql) } if len(ids) > 0 { structValue := reflect.Indirect(reflect.ValueOf(bean)) id := ids[0] - + session.Engine.LogDebug("[xorm:cacheGet] get bean:", tableName, id) cacheBean := cacher.GetBean(tableName, id) if cacheBean == nil { newSession := session.Engine.NewSession() @@ -436,10 +437,10 @@ func (session *Session) cacheGet(bean interface{}, sql string, args ...interface return has, err } - session.Engine.LogDebug("[xorm:cache] cache bean:", tableName, id, cacheBean) + session.Engine.LogDebug("[xorm:cacheGet] cache bean:", tableName, id, cacheBean) cacher.PutBean(tableName, id, cacheBean) } else { - session.Engine.LogDebug("[xorm:cache] cached bean:", tableName, id, cacheBean) + session.Engine.LogDebug("[xorm:cacheGet] cached bean:", tableName, id, cacheBean) has = true } structValue.Set(reflect.Indirect(reflect.ValueOf(cacheBean))) @@ -474,7 +475,7 @@ func (session *Session) cacheFind(t reflect.Type, sql string, rowsSlicePtr inter } // 查询数目太大,采用缓存将不是一个很好的方式。 if len(resultsSlice) > 100 { - session.Engine.LogDebug("[xorm:cache] ids > 100, no cache") + session.Engine.LogDebug("[xorm:cacheFind] ids > 100, no cache") return ErrCacheFailed } @@ -495,13 +496,13 @@ func (session *Session) cacheFind(t reflect.Type, sql string, rowsSlicePtr inter ids = append(ids, id) } } - session.Engine.LogDebug("[xorm:cache] cache ids:", ids, tableName, newsql, args) + session.Engine.LogDebug("[xorm:cacheFind] cache ids:", ids, tableName, newsql, args) err = putCacheSql(cacher, ids, tableName, newsql, args) if err != nil { return err } } else { - session.Engine.LogDebug("[xorm:cache] cached sql:", newsql, args) + session.Engine.LogDebug("[xorm:cacheFind] cached sql:", newsql, args) } sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) @@ -515,7 +516,7 @@ func (session *Session) cacheFind(t reflect.Type, sql string, rowsSlicePtr inter idxes = append(idxes, idx) ides = append(ides, id) } else { - session.Engine.LogDebug("[xorm:cache] cached bean:", tableName, id, bean) + session.Engine.LogDebug("[xorm:cacheFind] cached bean:", tableName, id, bean) temps[idx] = bean } } @@ -534,7 +535,7 @@ func (session *Session) cacheFind(t reflect.Type, sql string, rowsSlicePtr inter for i := 0; i < vs.Len(); i++ { bean := vs.Index(i).Addr().Interface() temps[idxes[i]] = bean - session.Engine.LogDebug("[xorm:cache] cache bean:", tableName, ides[i], bean) + session.Engine.LogDebug("[xorm:cacheFind] cache bean:", tableName, ides[i], bean) cacher.PutBean(tableName, ides[i].(int64), bean) } } @@ -544,13 +545,11 @@ func (session *Session) cacheFind(t reflect.Type, sql string, rowsSlicePtr inter if bean != nil { sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(bean)))) } else { - session.Engine.LogDebug("[xorm:cache] cache delete:", tableName, ides[j]) + session.Engine.LogDebug("[xorm:cacheFind] cache delete:", tableName, ides[j]) cacher.DelBean(tableName, ids[j]) - session.Engine.LogDebug("[xorm:cache] cache clear:", tableName) - fmt.Println(cacher) + session.Engine.LogDebug("[xorm:cacheFind] cache clear:", tableName) cacher.ClearIds(tableName) - fmt.Println(cacher) } } @@ -595,10 +594,7 @@ func (session *Session) Get(bean interface{}) (bool, error) { return false, nil } - results := resultsSlice[0] - - err = session.scanMapIntoStruct(bean, results) - + err = session.scanMapIntoStruct(bean, resultsSlice[0]) if err != nil { return true, err } @@ -1311,14 +1307,26 @@ func (statement *Statement) convertUpdateSql(sql string) (string, string) { if statement.RefTable == nil || statement.RefTable.PrimaryKey == "" { return "", "" } - sqls := strings.SplitN(strings.ToLower(sql), "where", 2) + idx := strings.Index(strings.ToLower(sql), "where") + sqls := strings.SplitN(sql, sql[idx:idx+5], 2) if len(sqls) != 2 { return "", "" } + var whereStr = sqls[1] + //TODO: for postgres only, if any other database? + if strings.Contains(sqls[1], "$") { + dollers := strings.Split(sqls[1], "$") + whereStr = dollers[0] + for i, c := range dollers[1:] { + ccs := strings.SplitN(c, " ", 2) + whereStr += fmt.Sprintf("$%v %v", i+1, ccs[1]) + } + } + return sqls[0], fmt.Sprintf("SELECT %v FROM %v WHERE %v", statement.Engine.Quote(statement.RefTable.PrimaryKey), statement.Engine.Quote(statement.TableName()), - sqls[1]) + whereStr) } func (session *Session) cacheInsert(tables ...string) error { @@ -1342,14 +1350,14 @@ func (session *Session) cacheUpdate(sql string, args ...interface{}) error { return ErrCacheFailed } - for _, filter := range session.Engine.Filters { - sql = filter.Do(sql, session) - } - oldhead, newsql := session.Statement.convertUpdateSql(sql) if newsql == "" { return ErrCacheFailed } + for _, filter := range session.Engine.Filters { + newsql = filter.Do(newsql, session) + } + session.Engine.LogDebug("[xorm:cacheUpdate] new sql", oldhead, newsql) var nStart int if len(args) > 0 { @@ -1363,12 +1371,15 @@ func (session *Session) cacheUpdate(sql string, args ...interface{}) error { table := session.Statement.RefTable cacher := table.Cacher tableName := session.Statement.TableName() - ids, err := getCacheSql(cacher, tableName, newsql, args) + session.Engine.LogDebug("[xorm:cacheUpdate] get cache sql", newsql, args[nStart:]) + ids, err := getCacheSql(cacher, tableName, newsql, args[nStart:]) if err != nil { resultsSlice, err := session.query(newsql, args[nStart:]...) if err != nil { return err } + session.Engine.LogDebug("[xorm:cacheUpdate] find updated id", resultsSlice) + ids = make([]int64, 0) if len(resultsSlice) > 0 { for _, data := range resultsSlice { @@ -1385,7 +1396,7 @@ func (session *Session) cacheUpdate(sql string, args ...interface{}) error { } } } else { - session.Engine.LogDebug("[xorm:cache] del cached sql:", tableName, newsql, args) + session.Engine.LogDebug("[xorm:cacheUpdate] del cached sql:", tableName, newsql, args) cacher.DelIds(tableName, genSqlKey(newsql, args)) } @@ -1410,13 +1421,16 @@ func (session *Session) cacheUpdate(sql string, args ...interface{}) error { colName = strings.TrimSpace(strings.Replace(colName, session.Engine.QuoteStr(), "", -1)) } //fmt.Println("find", colName) + if col, ok := table.Columns[colName]; ok { fieldValue := col.ValueOf(bean) + session.Engine.LogDebug("[xorm:cacheUpdate] set bean field", bean, colName, fieldValue.Interface()) //session.bytes2Value(col, fieldValue, []byte(args[idx])) fieldValue.Set(reflect.ValueOf(args[idx])) } } + session.Engine.LogDebug("[xorm:cacheUpdate] update cache", tableName, id, bean) cacher.PutBean(tableName, id, bean) } }