github.com/woocoos/entcache@v0.0.0-20231206055445-856f0148efa5/README.md (about) 1 # EntCache 2 3 本项目灵感来源于 [ariga.io/entcache](https://github.com/ariga/entcache). 在数据缓存方面强化, 如果需要使用上下文缓存,请使用源项目. 4 5 在使用过程中,发现源项目在缓存方面有一些不足,比如: 6 7 - 无法影响数据变化. 比如在缓存中的数据,在数据库中被发生变更时,缓存中的数据无法获得通知. 8 - 缓存时间需要显示控制, 如某些查询需要长时间缓存,某些查询需要短时间缓存. 9 10 为了缓存该问题,项目结合了Ent的Hooks机制与模板功能的配合使用,针对中某些特定的查询,如Get方法以及Graphql中Noder查询.在约定的开发模式下, 11 尽量在发生数据变更后,UI能尽快的获取到最新的数据. 12 13 本项目并未实现在自行查询上的同步缓存更新,因此还需要使用者在开发过程中, 显式通过context的使用来合理的使用缓存. 14 15 ## 设计 16 17 ### 查询类型 18 19 在缓存KV中, 统一采用查询语句的Hash值做为键,来避免不同的库表命名冲空.但在查询方式中,我们区分了两种查询类型: 20 21 - Hash: 是开发者自定义的查询. 22 - Key: 通过主键获取的数据的查询, 如Client.Get(context.Context, id any)同源的方法(如Only). 能主动影响数据变化. 23 24 对于这两种类型的查询,可以设定不同的缓存时间. 一般来说,Hash类型的查询,缓存时间会比较短,Key类型的查询,缓存时间会比较长. 25 26 ### Key查询的淘汰 27 28 Key类型的缓存由发现变化到变化结束,其变化结束控制点在于Get触发执行,如果Get未执行时,则变化标记一直存在. 29 30 针对同源查询的缓存淘汰处理如下: 31 32 - 在标记期间,如果标记时间超过了上一次查询的缓存时间,则会触发缓存淘汰, 以更新最新的数据. 33 - 在标记期间,如果不存在Hash值(变更后的第一次查询),则会触发缓存淘汰,防止变化前的缓存. 34 - 未在标记期间的查询,如存在Hash值,则触发缓存淘汰.该Hash值的存储只在标记期间,存在说明存在旧数据. 35 36 ### 内置缓存 37 38 内置的实现了Cache接口的TinyLFU缓存. 39 40 ## 使用 41 42 ``` 43 go get github.com/woocoos/entcache 44 ``` 45 46 在需要使用的Schema中,引入Hooks: 47 48 ```go 49 func (User) Hooks() []ent.Hook { 50 return []ent.Hook{ 51 entcache.DataChangeNotify(), 52 } 53 } 54 ``` 55 56 我们可通过配置方式, 初始化Driver. 57 ```yaml 58 entcache: 59 # 可选, Hash类型查询的缓存时间,如果使用内置缓存,则为内置缓存的缓存时间. 60 hashQueryTTL: 10s 61 keyQueryTTL: 1h 62 # 可选, 指定注册的缓存组件. 63 cacheKey: entcache 64 # 可选, 缓存前缀, 如果共用缓存组件则会有用. 65 cachePrefix: "admin:" 66 ``` 67 68 ```go 69 // cnf 为配置组件 70 drv := entcache.NewDriver(entcache.Configuration(cnf.sub("entcache"))) 71 client := ent.NewClient(ent.Driver(drv)) 72 // 启用监听 73 go drv.Start(context.Background()) 74 ``` 75 76 就可在代码中使用缓存了. 77 ```go 78 ctx := entcache.WithEntryKey(context.Background(), "User", 1) 79 client.User.Get(ctx, 1) 80 ``` 81 82 ### 利用模板简化 83 84 在context的写法有些麻烦是不,并且还会传入无关的Key, 对变更也不友好. 85 86 我们内置对Ent Client模板的修改,在生成的代码中,让Get自动引入了缓存的上下文,可在`entc`使用如: 87 88 ```go 89 func main() { 90 // .... 91 opts := []entc.Option{ 92 cachegen.QueryCache(), 93 } 94 if err := entc.Generate("./schema", &gen.Config{}, opts...); err != nil { 95 log.Fatalf("running ent codegen: %v", err) 96 } 97 } 98 99 ``` 100 101 Get方法就像平常那样使用了 102 103 如果你的项目已经存在模板的修改,那你已经知道怎么修改模板了,可以把调整模板的代码拷贝过来到你的模板中. 104 105 entgql也是同理修改,你可参考[TODO](integration/todo/ent/template/node.tmpl)中的修改.