8treenet / gcache Goto Github PK
View Code? Open in Web Editor NEWgcache是gorm的中间件,插入后gorm即刻拥有缓存。
License: Apache License 2.0
gcache是gorm的中间件,插入后gorm即刻拥有缓存。
License: Apache License 2.0
可以出一个分支支持gorm v2版本吗?
如题。首先非常感谢作者开发了这个牛逼的库哈哈。😁
我这里会经常用到关联的方法 related 和 association, 但是今天发现这种事不会缓存的,特别是使用preload的时候。
不知道是不是我的用法有问题或者是本身就不支持缓存?
result := dao.db.Where(&Item{RoleID: roleID}).Find(&items)
报错信息:“reflect: call of reflect.Value.FieldByName on ptr Value”
是怎么实现防缓存击穿的呀,如果在缓存失效的瞬间查询,查询结果是怎么样的,看代码没太看明白……
如下代码, TestPreloadSkipCache
能通过, TestPreload
会失败:
type TestRole struct {
gorm.Model
Name string
}
type TestUser struct {
gorm.Model
UserName string `gorm:"size:32"`
Password string `gorm:"size:32"`
Age int
Status int
Roles []TestRole `gorm:"many2many:test_user_roles;"`
}
func init() {
var e error
addr := "user=lab password=lab dbname=lab port=5432 sslmode=disable"
db, e = gorm.Open("postgres", addr)
if e != nil {
panic(e)
}
db.AutoMigrate(&TestRole{})
db.AutoMigrate(&TestUser{})
db.AutoMigrate(&TestEmail{})
opt := gcache.DefaultOption{}
opt.Expires = 300 //缓存时间,默认60秒。范围 30-900
opt.Level = gcache.LevelSearch //缓存级别,默认LevelSearch。LevelDisable:关闭缓存,LevelModel:模型缓存, LevelSearch:查询缓存
opt.AsyncWrite = false //异步缓存更新, 默认false。 insert update delete 成功后是否异步更新缓存
opt.PenetrationSafe = false //开启防穿透, 默认false。
//缓存中间件 注入到Gorm
cachePlugin = gcache.AttachDB(db, &opt, &gcache.RedisOption{Addr: "localhost:6379"})
InitData()
//开启Debug,查看日志
db.LogMode(true)
cachePlugin.Debug()
}
func InitData() {
cachePlugin.FlushDB()
db.Exec("truncate test_user_roles")
db.Exec("truncate test_roles")
db.Exec("truncate test_users")
db.Exec("truncate test_emails")
roleAdmin := &TestRole{
Name: "ADMIN",
}
db.Save(roleAdmin)
roleUser := &TestRole{
Name: "USER",
}
db.Save(roleUser)
for index := 1; index < 21; index++ {
user := &TestUser{}
user.UserName = fmt.Sprintf("%s_%d", "name", index)
user.Password = fmt.Sprintf("%s_%d", "password", index)
user.Age = 20 + index
user.Status = rand.Intn(3)
user.Roles = []TestRole{*roleUser, *roleAdmin}
db.Save(user)
email := &TestEmail{}
email.TypeID = index
email.TestUserID = index
db.Save(email)
}
}
func TestPreloadSkipCache(t *testing.T) {
var tc TestUser
db.First(&tc, "user_name = ?", "name_1")
assert.Equal(t, "name_1", tc.UserName)
assert.Equal(t, 0, len(tc.Roles))
cachePlugin.SkipCache().Preload("Roles").Find(&tc)
assert.Equal(t, 2, len(tc.Roles))
}
func TestPreload(t *testing.T) {
var tc TestUser
db.First(&tc, "user_name = ?", "name_1")
assert.Equal(t, "name_1", tc.UserName)
assert.Equal(t, 0, len(tc.Roles))
db.Preload("Roles").Find(&tc)
assert.Equal(t, 2, len(tc.Roles)) // FAIL
}
CreateRelative() 这个函数是不是只有关联查询的时候才需要用到,具体使用逻辑是什么?
tag 的作用是什么?
src\github.com\8treenet\gcache\internal\easy_scope.go:295:10: es.IsCompleteParentheses undefined (type *easyScope has no field or method IsCompleteParentheses)
类似的错误很容易发生,能看出来是什么原因吗:
panic: reflect: call of reflect.Value.FieldByName on ptr Value
goroutine 67 [running]:
github.com/jinzhu/gorm.(*Scope).callCallbacks.func1(0xc000113d80)
/root/go/pkg/mod/github.com/jinzhu/[email protected]/scope.go:865 +0xb0
panic(0x13b4ea0, 0xc00063cbc0)
/home/jenkins/tools/org.jenkinsci.plugins.golang.GolangInstallation/go-lang-1.13/src/runtime/panic.go:679 +0x1b2
reflect.flag.mustBe(...)
/home/jenkins/tools/org.jenkinsci.plugins.golang.GolangInstallation/go-lang-1.13/src/reflect/value.go:208
reflect.Value.FieldByName(0x13aad00, 0xc00063cba0, 0x196, 0x121f13c, 0x2, 0xc00063cba0, 0x196, 0xc00060d640)
/home/jenkins/tools/org.jenkinsci.plugins.golang.GolangInstallation/go-lang-1.13/src/reflect/value.go:890 +0x1ed
github.com/8treenet/gcache/internal.(*easyScope).EasyPrimarys(0xc0004ccb00, 0x1616ed8, 0x8, 0xc0000486c0, 0x3c, 0xc00060d630)
/root/go/pkg/mod/github.com/8treenet/[email protected]/internal/easy_scope.go:497 +0xbcf
github.com/8treenet/gcache/internal.(*queryHandle).BySearch(0xc0000196f8, 0xc0004ccb00, 0xc00063c080, 0x197, 0x203000, 0x203000, 0x203000)
/root/go/pkg/mod/github.com/8treenet/[email protected]/internal/handle_query.go:109 +0xf7
github.com/8treenet/gcache/internal.(*callQuery).bySearch(0xc0003cc340, 0xc0004ccb00, 0x0, 0x0, 0x0, 0x0)
/root/go/pkg/mod/github.com/8treenet/[email protected]/internal/call_query.go:118 +0xd6
github.com/8treenet/gcache/internal.(*callQuery).invoke.func1(0x413031, 0xd0, 0x14a1860, 0xfba41cc9035f6801)
/root/go/pkg/mod/github.com/8treenet/[email protected]/internal/call_query.go:53 +0x75
github.com/8treenet/gcache/internal.(*Group).doCall(0xc0003cc348, 0xc000491f20, 0xc000040690, 0x4c, 0xc0000198a0)
/root/go/pkg/mod/github.com/8treenet/[email protected]/internal/singleflight.go:91 +0x2e
github.com/8treenet/gcache/internal.(*Group).Do(0xc0003cc348, 0xc000040690, 0x4c, 0xc0000198a0, 0xe, 0xc00060d5c8, 0x2, 0xc000040690, 0x4c)
/root/go/pkg/mod/github.com/8treenet/[email protected]/internal/singleflight.go:61 +0x1ba
github.com/8treenet/gcache/internal.(*callQuery).invoke(0xc0003cc340, 0xc000113d80)
/root/go/pkg/mod/github.com/8treenet/[email protected]/internal/call_query.go:46 +0x1a8
github.com/jinzhu/gorm.(*Scope).callCallbacks(0xc000113d80, 0xc0003cce20, 0x4, 0x4, 0x0)
/root/go/pkg/mod/github.com/jinzhu/[email protected]/scope.go:869 +0x92
github.com/jinzhu/gorm.(*DB).Find(0xc0003e8270, 0x12caea0, 0xc00063c080, 0xc000633950, 0x3, 0x3, 0xc000633950)
/root/go/pkg/mod/github.com/jinzhu/[email protected]/main.go:354 +0x98
gitlab.com/example/dal/reader.(*Reader).GetProducts(0xc00048f580, 0xc000633950, 0x3, 0x3, 0xc00063c060, 0x2, 0x2, 0x2, 0xc0004d4240)
/home/jenkins/workspace/example/dal/reader/product.go:19 +0xb4
gitlab.com/sensestar/example/payment/controllers.(*PaymentController).GetProducts(0x27c54b0, 0x19ed8e0, 0xc0005006c0, 0xc0004d4240, 0x27c54b0, 0xc0005006c0, 0xc000027b58)
/home/jenkins/workspace/example/payment/controllers/payment.go:72 +0x4ee
gitlab.com/sensestar/example/payment._PaymentService_GetProducts_Handler(0x15ede00, 0x27c54b0, 0x19ed8e0, 0xc0005006c0, 0xc000490f60, 0x0, 0x19ed8e0, 0xc0005006c0, 0xc0004deb10, 0x10)
/home/jenkins/workspace/example/payment/payment.pb.go:5483 +0x217
google.golang.org/grpc.(*Server).processUnaryRPC(0xc000210d00, 0x1a04620, 0xc0000ebe00, 0xc0004cc300, 0xc000089800, 0x2788aa0, 0x0, 0x0, 0x0)
/root/go/pkg/mod/google.golang.org/[email protected]/server.go:1082 +0x4fd
google.golang.org/grpc.(*Server).handleStream(0xc000210d00, 0x1a04620, 0xc0000ebe00, 0xc0004cc300, 0x0)
/root/go/pkg/mod/google.golang.org/[email protected]/server.go:1405 +0xd27
google.golang.org/grpc.(*Server).serveStreams.func1.1(0xc0004de9b0, 0xc000210d00, 0x1a04620, 0xc0000ebe00, 0xc0004cc300)
/root/go/pkg/mod/google.golang.org/[email protected]/server.go:746 +0xbb
created by google.golang.org/grpc.(*Server).serveStreams.func1
/root/go/pkg/mod/google.golang.org/[email protected]/server.go:744 +0xa1
RT。可以做成不依赖于某个具体的ORM。
感谢你的项目,很有帮助。
根据主键查询为什么不能缓存呢?
比如
db.Where("id = ?", 1).Take(&record)
这种语句就不能缓存,还是我哪里理解错了呢?谢谢。
请问如何hook gorm的呢?能大概说一下你的思路吗?或者有相关资料介绍?谢谢。
缓存是存在内存里的吗?如果应用有多个实例咋办
比如有 ABC 三个实例,在 A 实例中 insert 了个东西,
然后后面请求打到 B 实例, update 这条记录,我理解这时候 A 里的缓存是不是不会被更新,就读到旧数据了。
Any plans on v2 support? gorm.io/gorm
测试代码如下:
func TestAssociation(t *testing.T) {
var tc TestUser
db.First(&tc, "user_name = ?", "name_1")
assert.Equal(t, "name_1", tc.UserName)
assert.Equal(t, 0, len(tc.Roles))
cachePlugin.SkipCache().Preload("Roles").Find(&tc)
assert.Equal(t, 2, len(tc.Roles))
db.Preload("Roles").Find(&tc)
assert.Equal(t, 2, len(tc.Roles))
var adminRole TestRole
db.Model(&adminRole).Where("name = ?", "ADMIN").First(&adminRole)
assert.Equal(t, "ADMIN", adminRole.Name)
db.Model(tc).Association("Roles").Delete(adminRole) // panic: reflect.Value.Addr of unaddressable value
}
这个删除操作会导致 panic: reflect.Value.Addr of unaddressable value
,测试了去掉 gcache 是能通过测试的。
Other code see #16, full code see https://github.com/8treenet/gcache/compare/master...sutra:testAssociation?expand=1
单个接口调用mysql 并且接入了缓存 没有什么问题 但是同时并非请求 这边直接500了
在执行
golang: querys:=db.Table("dsp_campaign_frequercy").Find(&dCF).Scan(&dCF)
sql : select *from dsp_campaign_frequercy;
发现,并没有将查询出来的数据,插入到redis中,请问如何将全表数据,一次插入到redis中。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.