THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Browse Source

Get adds context cache feature (#1102)

* context

* add context cache feature

* remove global context cache

* remove global context cache

* reset statment

* fix bug

* remove unused params

* refactor ContextCache

* refactor ContextCache

* update README

* update README

* disable global cache on context cache test
tags/v0.7.1
Lunny Xiao GitHub 1 year ago
parent
commit
7a9249de33
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 232 additions and 1 deletions
  1. +52
    -0
      README.md
  2. +52
    -0
      README_CN.md
  3. +30
    -0
      context_cache.go
  4. +6
    -0
      session.go
  5. +23
    -1
      session_get.go
  6. +67
    -0
      session_get_test.go
  7. +2
    -0
      statement.go

+ 52
- 0
README.md View File

@@ -34,6 +34,8 @@ Xorm is a simple and powerful ORM for Go.

* Postgres schema support

* Context Cache support

## Drivers Support

Drivers for Go's sql package which currently support database/sql includes:
@@ -358,6 +360,56 @@ if _, err := session.Exec("delete from userinfo where username = ?", user2.Usern
return session.Commit()
```

* Or you can use `Transaction` to replace above codes.

```Go
res, err := engine.Transaction(func(sess *xorm.Session) (interface{}, error) {
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return nil, err
}

user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return nil, err
}

if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return nil, err
}
return nil, nil
})
```

* Context Cache, if enabled, current query result will be cached on session and be used by next same statement on the same session.

```Go
sess := engine.NewSession()
defer sess.Close()

var context = xorm.NewMemoryContextCache()

var c2 ContextGetStruct
has, err := sess.ID(1).ContextCache(context).Get(&c2)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 1, c2.Id)
assert.EqualValues(t, "1", c2.Name)
sql, args := sess.LastSQL()
assert.True(t, len(sql) > 0)
assert.True(t, len(args) > 0)

var c3 ContextGetStruct
has, err = sess.ID(1).ContextCache(context).Get(&c3)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 1, c3.Id)
assert.EqualValues(t, "1", c3.Name)
sql, args = sess.LastSQL()
assert.True(t, len(sql) == 0)
assert.True(t, len(args) == 0)
```

## Contributing

If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md). And we also provide [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm) to discuss.


+ 52
- 0
README_CN.md View File

@@ -32,6 +32,8 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作

* 内置SQL Builder支持

* 上下文缓存支持

## 驱动支持

目前支持的Go数据库驱动和对应的数据库如下:
@@ -360,6 +362,56 @@ if _, err := session.Exec("delete from userinfo where username = ?", user2.Usern
return session.Commit()
```

* 事物的简写方法

```Go
res, err := engine.Transaction(func(sess *xorm.Session) (interface{}, error) {
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return nil, err
}

user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return nil, err
}

if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return nil, err
}
return nil, nil
})
```

* Context Cache, if enabled, current query result will be cached on session and be used by next same statement on the same session.

```Go
sess := engine.NewSession()
defer sess.Close()

var context = xorm.NewMemoryContextCache()

var c2 ContextGetStruct
has, err := sess.ID(1).ContextCache(context).Get(&c2)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 1, c2.Id)
assert.EqualValues(t, "1", c2.Name)
sql, args := sess.LastSQL()
assert.True(t, len(sql) > 0)
assert.True(t, len(args) > 0)

var c3 ContextGetStruct
has, err = sess.ID(1).ContextCache(context).Get(&c3)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 1, c3.Id)
assert.EqualValues(t, "1", c3.Name)
sql, args = sess.LastSQL()
assert.True(t, len(sql) == 0)
assert.True(t, len(args) == 0)
```

## 贡献

如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)。您也可以加入QQ群 技术帮助和讨论。


+ 30
- 0
context_cache.go View File

@@ -0,0 +1,30 @@
// Copyright 2018 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package xorm

// ContextCache is the interface that operates the cache data.
type ContextCache interface {
// Put puts value into cache with key.
Put(key string, val interface{})
// Get gets cached value by given key.
Get(key string) interface{}
}

type memoryContextCache map[string]interface{}

// NewMemoryContextCache return memoryContextCache
func NewMemoryContextCache() memoryContextCache {
return make(map[string]interface{})
}

// Put puts value into cache with key.
func (m memoryContextCache) Put(key string, val interface{}) {
m[key] = val
}

// Get gets cached value by given key.
func (m memoryContextCache) Get(key string) interface{} {
return m[key]
}

+ 6
- 0
session.go View File

@@ -102,6 +102,12 @@ func (session *Session) Close() {
}
}

// ContextCache enable context cache or not
func (session *Session) ContextCache(context ContextCache) *Session {
session.statement.context = context
return session
}

// IsClosed returns if session is closed
func (session *Session) IsClosed() bool {
return session.db == nil


+ 23
- 1
session_get.go View File

@@ -7,6 +7,7 @@ package xorm
import (
"database/sql"
"errors"
"fmt"
"reflect"
"strconv"

@@ -66,7 +67,28 @@ func (session *Session) get(bean interface{}) (bool, error) {
}
}

return session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
context := session.statement.context
if context != nil {
res := context.Get(fmt.Sprintf("%v-%v", sqlStr, args))
if res != nil {
structValue := reflect.Indirect(reflect.ValueOf(bean))
structValue.Set(reflect.Indirect(reflect.ValueOf(res)))
session.lastSQL = ""
session.lastSQLArgs = nil
return true, nil
}
}

has, err := session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
if err != nil || !has {
return has, err
}

if context != nil {
context.Put(fmt.Sprintf("%v-%v", sqlStr, args), bean)
}

return true, nil
}

func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {


+ 67
- 0
session_get_test.go View File

@@ -319,3 +319,70 @@ func TestGetStructId(t *testing.T) {
assert.True(t, has)
assert.EqualValues(t, 2, maxid.Id)
}

func TestContextGet(t *testing.T) {
type ContextGetStruct struct {
Id int64
Name string
}

assert.NoError(t, prepareEngine())
assertSync(t, new(ContextGetStruct))

_, err := testEngine.Insert(&ContextGetStruct{Name: "1"})
assert.NoError(t, err)

sess := testEngine.NewSession()
defer sess.Close()

context := NewMemoryContextCache()

var c2 ContextGetStruct
has, err := sess.ID(1).NoCache().ContextCache(context).Get(&c2)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 1, c2.Id)
assert.EqualValues(t, "1", c2.Name)
sql, args := sess.LastSQL()
assert.True(t, len(sql) > 0)
assert.True(t, len(args) > 0)

var c3 ContextGetStruct
has, err = sess.ID(1).NoCache().ContextCache(context).Get(&c3)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 1, c3.Id)
assert.EqualValues(t, "1", c3.Name)
sql, args = sess.LastSQL()
assert.True(t, len(sql) == 0)
assert.True(t, len(args) == 0)
}

func TestContextGet2(t *testing.T) {
type ContextGetStruct2 struct {
Id int64
Name string
}

assert.NoError(t, prepareEngine())
assertSync(t, new(ContextGetStruct2))

_, err := testEngine.Insert(&ContextGetStruct2{Name: "1"})
assert.NoError(t, err)

context := NewMemoryContextCache()

var c2 ContextGetStruct2
has, err := testEngine.ID(1).NoCache().ContextCache(context).Get(&c2)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 1, c2.Id)
assert.EqualValues(t, "1", c2.Name)

var c3 ContextGetStruct2
has, err = testEngine.ID(1).NoCache().ContextCache(context).Get(&c3)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 1, c3.Id)
assert.EqualValues(t, "1", c3.Name)
}

+ 2
- 0
statement.go View File

@@ -59,6 +59,7 @@ type Statement struct {
exprColumns map[string]exprParam
cond builder.Cond
bufferSize int
context ContextCache
}

// Init reset all the statement's fields
@@ -99,6 +100,7 @@ func (statement *Statement) Init() {
statement.exprColumns = make(map[string]exprParam)
statement.cond = builder.NewCond()
statement.bufferSize = 0
statement.context = nil
}

// NoAutoCondition if you do not want convert bean's field as query condition, then use this function


Loading…
Cancel
Save