diff --git a/docs/uniCloud/jql-cache-redis.md b/docs/uniCloud/jql-cache-redis.md index f295e8b6b335cf3eed6b37f655b926a7cc80ff22..ef510dfe1dfbfccbdcc777ff580ea9262688cb59 100644 --- a/docs/uniCloud/jql-cache-redis.md +++ b/docs/uniCloud/jql-cache-redis.md @@ -1,45 +1,120 @@ > 新增于HBuilderX 3.5.2,需先开通[redis](uniCloud/redis-introduction.md) -业务中经常遇到不常改动或不需要及时更新的数据,此时如果每次都去数据库读取会浪费数据库读写次数,并且会增加云函数运行时间导致云函数整体能处理的请求数量变低。为了应对这种情况,jql支持了将配置的查询指令的结果缓存在redis内的功能。 +## JQL Cache Redis -详细用法如下 +uniCloud 提供了 MongoDB 和 Redis 2种数据库。并且提供了联动机制,可以方便的将 MongoDB 中的数据缓存到 Redis 中。 -1. 在插件市场导入`uni-config-center`插件,插件地址:[uni-config-center](https://ext.dcloud.net.cn/plugin?id=4425) -2. 在`uniCloud/cloudfunction/common/uni-config-center`下创建`uni-jql-cache-redis.json`文件(注意此文件是标准json格式,不支持注释) +适用场景: - 整个`uni-jql-cache-redis.json`文件是一个数组,其中每一项是一个缓存配置。示例内容如下 +需要频繁访问,但不会频繁修改的数据。比如更新不频繁的首页列表、banner、热搜、top排行等公共数据。 - ```js - [{ - "id": "test-get", // 缓存id - "jql": "db.collection('test').limit(10).get()", // 要缓存的数据库指令 - "expiresIn": 3600 // 缓存有效期 - }] - ``` +这些查询请求频次高,如果每次都去MongoDB读取,又慢又贵,还可能超时或超并发。 -3. 配置成功后与配置匹配的clientDB请求及使用jql扩展库的数据库查询会优先使用redis缓存(第一次调用匹配的查询语句时会先设置一次缓存) +使用`JQL Cache Redis`,就可以方便的将这些查询结果缓存在 Redis 中。即提示了访问速度,又提升了并发性能,还减少了云函数运行时长和数据库读取次数。 -未命中缓存时,clientDB或使用了jql扩展的云函数云函数会输出以下日志 +- 不管 clientDB 的组件还是API,或者云函数/云对象JQL,都可以使用`JQL Cache Redis` +- 但 JQL管理器不支持,此调试工具只能直接查询 MongoDB +- 云函数/云对象中使用`JQL Cache Redis`需加载 Redis 和 JQL 扩展库,并依赖`uni-config-center`公共模块 +- 本地运行也支持 + +## 原理 +1. 开发者在`uni-config-center`中配置指定 JQL 查询指令 +2. 客户端或云函数进行 JQL 查询时会判断当前指令是否被提前配置 + - 2.1 如未配置,继续进行普通查询连接 MongoDB + - 2.2 如已配置,则去 Redis 中获取查询结果 + * 2.2.1 如在 Redis 中查到结果,返回查询结果 + * 2.2.2 如发现 Redis 中无缓存结果或缓存过期,则再次连接 MongoDB 查询,返回查询结果的同时自动将该结果同步给 Redis。下次再访问就可以走 Redis 了。 +3. 如果开发者更新了MongoDB里的数据,需调用 API让 Redis 中指定的缓存失效 [见下](#del-cache) + +## 配置方法 + +在`uniCloud/cloudfunction/common/uni-config-center`下创建`uni-jql-cache-redis.json`文件(注意此文件是标准json格式,不支持注释) + +如未安装`uni-config-center`,请在插件市场导入,插件地址:[uni-config-center](https://ext.dcloud.net.cn/plugin?id=4425) + +`uni-jql-cache-redis.json`文件是一个数组,其中每一项是一个缓存配置。示例内容如下 + +```js +[{ + "id": "test-get", // 缓存id,不可重复,必填 + "jql": "db.collection('test').limit(10).get()", // 要缓存的数据库指令,必填 + "expiresIn": 3600 // 缓存有效期,单位秒,非必填 +}] +``` + +`expiresIn`如果不填,就意味着不会根据时间失效。 + +配置成功后,客户端或云端JQL查询`db.collection('test').limit(10).get()`时,就会优先去redis中找,如果没找到,会从MongoDB中找然后自动cache到redis中。 + + +未命中缓存时,clientDB或使用了jql扩展的云函数/云对象会输出以下日志 ```js "当前请求需使用Redis缓存" "返回Redis内缓存的结果" ``` -命中缓存时,clientDB或使用了jql扩展的云函数云函数会输出以下日志 +命中缓存时,clientDB或使用了jql扩展的云函数/云对象会输出以下日志 ```js "当前请求需使用Redis缓存" "未命中Redis缓存,设置Redis缓存" ``` -**缓存生效场景** +`JQL Cache Redis`会将缓存配置对应的查询结果缓存到key为`unicloud:jql-cache:${id}:string`的redis缓存内。可以在uniCloud web控制台的redis视图中找到。 + +配置`"jql": "db.collection('test').limit(10).get()"`时需注意,普通的JQL语句放在json的value中需要对引号转义,见下。 + +### 关于引号转义@escape-quote + +由于需要将查询语句放在json文件内,而json内字符串又需要引号包围,所以对于查询语句内使用双引号的场景需转义后再放到配置内。 + +例如: + +```js +// jql +db.collection('book').where('author=="caoxueqin"').get() + +// 转义后 +"db.collection('book').where('author==\"caoxueqin\"').get()" +``` + +如果你的查询语句比较复杂,自己一个个加转义符比较麻烦。可以通过如下方式获取转义后的字符串 + +1. 创建一个云函数内容如下 + +```js +'use strict'; +const fs = require('fs') +const path = require('path') +exports.main = async (event, context) => { + console.log( + fs.readFileSync( + path.resolve(__dirname, 'test.jql') + ).toString() + ) +}; +``` -- 所有clientDB查询请求 -- 启用redis扩展和jql扩展的云函数内的jql数据库查询请求 -- unicloud-db组件的查询请求 +2. 在云函数根目录创建一个`test.jql`文件,内容为要转义的jql查询语句 -jql会将缓存配置对应的查询结果缓存到key为`unicloud:jql-cache:${id}:string`redis缓存内 +```js +db.collection('book').where('author=="caoxueqin"').get() +``` + +3. 本地运行云函数,查看HBuilderX控制台的云函数日志输出 + +```text +21:56:44.135 [本地运行]"db.collection('book').where('author==\"caoxueqin\"').get()" uniCloud-aliyun/cloudfunctions/test/index.js:5:10 +``` + +### 注意事项 + +- 仅可缓存查询的JQL指令,增删改JQL指令无效 +- 不可缓存使用了`db.getCloudEnv()`或`$cloudEnv_`开头的云端环境变量的查询 +- 不可缓存使用了action的查询 +- 启用JQL扩展库的云函数/云对象同时也要启用Redis扩展库才可以正常使用缓存功能,否则依然从数据库查询 +- 配置后或设置缓存失效后,开发者可自己请求一次JQL查询,让cache生效。避免用户第一次访问时仍然访问MongoDB ## multiSend使用缓存@multi-send @@ -57,7 +132,7 @@ db.multiSend(book,author) 需要单独配置book表的查询语句和author表的查询语句,注意getTemp方法也需要改为get方法 -```js +```json [{ "id": "book-get", "jql": "db.collection('book').limit(10).get()", @@ -81,9 +156,9 @@ const author = db.collection('author').getTemp() db.collection(book, author).get() ``` -缓存配置如下 +`uni-jql-cache-redis.json`缓存配置如下 -```js +```json [{ "id": "book-author-lookup", "jql": "const book = db.collection('book').limit(10).getTemp();const author = db.collection('author').getTemp();db.collection(book, author).get()", @@ -93,22 +168,19 @@ db.collection(book, author).get() ## 删除redis缓存@del-cache -使用redis删除命令传入缓存对应的key即可删除缓存 +当MongoDB中的数据变更时,应该主动删除Redis中的缓存。 + +比如把banner轮播图的数据缓存在Redis中后,在admin中修改banner,应该同时在云函数中操作redis,将banner的缓存设为失效 + +使用redis删除命令传入缓存对应的key即可删除缓存。 例: ```js const redis = uniCloud.redis() -const id = 'book-author-lookup' +const id = 'banner' // 这个id就是`uni-jql-cache-redis.json`中配置的id const cacheKey = `unicloud:jql-cache:${id}:string` await redis.del(cacheKey) ``` -## 注意事项 -- 仅可缓存查询指令 -- 注意id为缓存唯一id,不可与其他项重复 -- 不可缓存使用了`db.getCloudEnv()`或`$cloudEnv_`开头的云端环境变量的查询 -- 不可缓存使用了action的查询 -- 不配置`expiresIn`时数据将会持久保存在redis内 -- 启用jql扩展库的云函数同时也要启用redis扩展库才可以正常使用缓存功能,否则依然从数据库查询 \ No newline at end of file