mm_cachebase 1.9.8 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +269 -559
- package/index.js +2075 -1324
- package/package.json +3 -3
- package/test.js +728 -536
package/README.md
CHANGED
|
@@ -1,559 +1,269 @@
|
|
|
1
|
-
# mm_cachebase
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## 项目信息
|
|
6
|
-
|
|
7
|
-
- **当前版本**:
|
|
8
|
-
- **更新日期**:
|
|
9
|
-
- **Gitee地址**: [https://gitee.com/qiuwenwu91/mm_cachebase](https://gitee.com/qiuwenwu91/mm_cachebase)
|
|
10
|
-
- **Node.js 版本要求**: >= 14.0.0(推荐 16.0.0 及以上)
|
|
11
|
-
|
|
12
|
-
## 特点
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
## 安装
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm install mm_cachebase
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## 基本使用
|
|
28
|
-
|
|
29
|
-
```javascript
|
|
30
|
-
const CacheBase = require('mm_cachebase');
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
const cache = new CacheBase();
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
##
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
```javascript
|
|
54
|
-
const cache = new CacheBase(scope
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
await cache.
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
await cache.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
```javascript
|
|
271
|
-
await cache.add(key, value, maxAge)
|
|
272
|
-
```
|
|
273
|
-
- 返回: 添加成功返回值,已存在返回0
|
|
274
|
-
|
|
275
|
-
#### 检查键是否存在
|
|
276
|
-
```javascript
|
|
277
|
-
await cache.has(key)
|
|
278
|
-
```
|
|
279
|
-
- 返回: 存在返回1,不存在返回0
|
|
280
|
-
|
|
281
|
-
#### 增加浮点数(兼容方法)
|
|
282
|
-
```javascript
|
|
283
|
-
await cache.addFloat(key, num, maxAge)
|
|
284
|
-
```
|
|
285
|
-
- `num`: 要增加的浮点数
|
|
286
|
-
- `maxAge`: 过期时间(秒),默认0表示永不过期
|
|
287
|
-
- 返回: 计算后的结果
|
|
288
|
-
|
|
289
|
-
#### 追加字符串(兼容方法)
|
|
290
|
-
```javascript
|
|
291
|
-
await cache.addStr(key, str, maxAge)
|
|
292
|
-
```
|
|
293
|
-
- `maxAge`: 过期时间(秒),默认0表示永不过期
|
|
294
|
-
- 返回: 追加后的完整字符串
|
|
295
|
-
|
|
296
|
-
#### 清空匹配缓存(兼容方法)
|
|
297
|
-
```javascript
|
|
298
|
-
await cache.clear(pattern)
|
|
299
|
-
```
|
|
300
|
-
- `pattern`: 可选,支持*通配符
|
|
301
|
-
|
|
302
|
-
## 事件系统
|
|
303
|
-
|
|
304
|
-
CacheBase 提供了完整的事件系统,允许你监听各种缓存操作的前后事件,以便进行日志记录、数据验证或操作取消等功能。
|
|
305
|
-
|
|
306
|
-
> **性能优化说明**:从版本 1.6.0 开始,查询类方法(如 get、hget、mget、exists、ttl 等)不再触发事件,以提高高频查询操作的性能。
|
|
307
|
-
|
|
308
|
-
### 事件监听方法
|
|
309
|
-
|
|
310
|
-
```javascript
|
|
311
|
-
// 监听事件
|
|
312
|
-
cache.on('event_name', callback);
|
|
313
|
-
|
|
314
|
-
// 监听一次性事件
|
|
315
|
-
cache.once('event_name', callback);
|
|
316
|
-
|
|
317
|
-
// 移除事件监听
|
|
318
|
-
cache.off('event_name', callback);
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
### 事件参数格式
|
|
322
|
-
|
|
323
|
-
所有事件的回调函数都会接收一个标准化的事件数据对象,包含以下属性:
|
|
324
|
-
|
|
325
|
-
- `key`: 操作的缓存键名(如果适用)
|
|
326
|
-
- `value`: 操作的值,可以是基本类型或包含多个属性的对象
|
|
327
|
-
- `result`: 操作的结果
|
|
328
|
-
- `error`: 错误信息(仅错误事件)
|
|
329
|
-
- `cancel`: 用于取消操作的标志(仅前置事件)
|
|
330
|
-
- `ttl`: 过期时间(秒)(仅过期时间相关操作)
|
|
331
|
-
|
|
332
|
-
### 支持的事件类型
|
|
333
|
-
|
|
334
|
-
每个缓存操作都有对应的前置事件(`_before`)、后置事件(`_after`)和错误事件(`_error`)。
|
|
335
|
-
|
|
336
|
-
#### 基本操作事件
|
|
337
|
-
- `set_before`, `set_after`, `set_error`
|
|
338
|
-
- `del_before`, `del_after`, `del_error`
|
|
339
|
-
- `mset_before`, `mset_after`, `mset_error`
|
|
340
|
-
|
|
341
|
-
#### 过期时间操作事件
|
|
342
|
-
- `expire_before`, `expire_after`, `expire_error`
|
|
343
|
-
- `persist_before`, `persist_after`, `persist_error`
|
|
344
|
-
|
|
345
|
-
#### 数值操作事件
|
|
346
|
-
- `incr_before`, `incr_after`, `incr_error`
|
|
347
|
-
- `decr_before`, `decr_after`, `decr_error`
|
|
348
|
-
- `incrby_before`, `incrby_after`, `incrby_error`
|
|
349
|
-
- `decrby_before`, `decrby_after`, `decrby_error`
|
|
350
|
-
- `incrbyfloat_before`, `incrbyfloat_after`, `incrbyfloat_error`
|
|
351
|
-
|
|
352
|
-
#### 字符串操作事件
|
|
353
|
-
- `append_before`, `append_after`, `append_error`
|
|
354
|
-
|
|
355
|
-
#### 哈希表操作事件
|
|
356
|
-
- `hset_before`, `hset_after`, `hset_error`
|
|
357
|
-
- `hdel_before`, `hdel_after`, `hdel_error`
|
|
358
|
-
|
|
359
|
-
#### 键操作事件
|
|
360
|
-
- `flushdb_before`, `flushdb_after`, `flushdb_error`
|
|
361
|
-
- `dispose_before`, `dispose_after`, `dispose_error`
|
|
362
|
-
|
|
363
|
-
### 事件使用示例
|
|
364
|
-
|
|
365
|
-
```javascript
|
|
366
|
-
const cache = new CacheBase();
|
|
367
|
-
|
|
368
|
-
// 监听设置操作的前置事件
|
|
369
|
-
cache.on('set_before', (data) => {
|
|
370
|
-
$.log.debug('即将设置键:', data.key, '值:', data.value);
|
|
371
|
-
|
|
372
|
-
// 数据验证示例
|
|
373
|
-
if (typeof data.value === 'string' && data.value.length > 100) {
|
|
374
|
-
$.log.debug('值长度过长,取消设置');
|
|
375
|
-
data.cancel = true; // 取消操作
|
|
376
|
-
}
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
// 错误事件监听
|
|
380
|
-
cache.on('mset_error', (data) => {
|
|
381
|
-
$.log.error(`批量设置出错: ${data.error.message}`);
|
|
382
|
-
});
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
## 使用示例
|
|
386
|
-
|
|
387
|
-
### 基本缓存操作
|
|
388
|
-
```javascript
|
|
389
|
-
const cache = new CacheBase();
|
|
390
|
-
|
|
391
|
-
async function example() {
|
|
392
|
-
// 设置缓存
|
|
393
|
-
await cache.set("user", "张三", 60); // 60秒后过期
|
|
394
|
-
|
|
395
|
-
// 获取缓存
|
|
396
|
-
const user = await cache.get("user");
|
|
397
|
-
$.log.debug(user); // 输出: 张三
|
|
398
|
-
|
|
399
|
-
// 检查是否存在
|
|
400
|
-
const exists = await cache.exists("user");
|
|
401
|
-
$.log.debug(exists); // 输出: 1
|
|
402
|
-
|
|
403
|
-
// 删除缓存
|
|
404
|
-
await cache.del("user");
|
|
405
|
-
}
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
### 哈希表操作示例
|
|
409
|
-
```javascript
|
|
410
|
-
async function hashExample() {
|
|
411
|
-
// 设置哈希表字段
|
|
412
|
-
await cache.hset("user:123", "name", "张三");
|
|
413
|
-
await cache.hset("user:123", "age", 30);
|
|
414
|
-
await cache.hset("user:123", "email", "zhangsan@example.com");
|
|
415
|
-
|
|
416
|
-
// 获取哈希表字段
|
|
417
|
-
const name = await cache.hget("user:123", "name");
|
|
418
|
-
$.log.debug(name); // 输出: 张三
|
|
419
|
-
|
|
420
|
-
// 获取所有字段和值
|
|
421
|
-
const user = await cache.hgetall("user:123");
|
|
422
|
-
$.log.debug(user); // 输出: { name: "张三", age: 30, email: "zhangsan@example.com" }
|
|
423
|
-
|
|
424
|
-
// 删除字段
|
|
425
|
-
await cache.hdel("user:123", "email");
|
|
426
|
-
}
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
### 数值操作示例
|
|
430
|
-
```javascript
|
|
431
|
-
async function numberExample() {
|
|
432
|
-
// 设置初始值
|
|
433
|
-
await cache.set("counter", 10);
|
|
434
|
-
|
|
435
|
-
// 增加1
|
|
436
|
-
const incr = await cache.incr("counter");
|
|
437
|
-
$.log.debug("增加后:", incr); // 输出: 11
|
|
438
|
-
|
|
439
|
-
// 增加指定值
|
|
440
|
-
const incrby = await cache.incrby("counter", 5);
|
|
441
|
-
$.log.debug("增加5后:", incrby); // 输出: 16
|
|
442
|
-
|
|
443
|
-
// 减少1
|
|
444
|
-
const decr = await cache.decr("counter");
|
|
445
|
-
$.log.debug("减少后:", decr); // 输出: 15
|
|
446
|
-
|
|
447
|
-
// 浮点数操作
|
|
448
|
-
await cache.set("price", 99.99);
|
|
449
|
-
const incrFloat = await cache.incrbyfloat("price", 0.01);
|
|
450
|
-
$.log.debug("浮点数增加后:", incrFloat); // 输出: 100
|
|
451
|
-
}
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
### 多文件持久化示例
|
|
455
|
-
```javascript
|
|
456
|
-
const CacheBase = require('mm_cachebase');
|
|
457
|
-
|
|
458
|
-
async function persistenceExample() {
|
|
459
|
-
// 创建启用持久化的缓存实例,指定不同的scope
|
|
460
|
-
const userCache = new CacheBase('users', {
|
|
461
|
-
persist: true,
|
|
462
|
-
saveInterval: 30000, // 30秒保存一次
|
|
463
|
-
dir: './test_cache/' // 自定义缓存目录
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
const productCache = new CacheBase('products', {
|
|
467
|
-
persist: true,
|
|
468
|
-
saveInterval: 30000,
|
|
469
|
-
dir: './test_cache/'
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
// 启动定时保存
|
|
473
|
-
await userCache.connect();
|
|
474
|
-
await productCache.connect();
|
|
475
|
-
|
|
476
|
-
// 向不同scope添加数据
|
|
477
|
-
await userCache.set('user1', { name: '张三', age: 30 }, 3600);
|
|
478
|
-
await productCache.set('product1', { id: 1, name: '商品A', price: 99.99 }, 3600);
|
|
479
|
-
|
|
480
|
-
// 数据会分别保存到 users.cache.json 和 products.cache.json
|
|
481
|
-
$.log.debug('数据已保存,不同scope的数据完全隔离');
|
|
482
|
-
|
|
483
|
-
// 手动保存(可选)
|
|
484
|
-
await userCache.save();
|
|
485
|
-
|
|
486
|
-
// 应用重启后,可通过相同的scope加载对应的数据
|
|
487
|
-
const loadedUserCache = new CacheBase('users', { persist: true, dir: './test_cache/' });
|
|
488
|
-
const loadedUser = await loadedUserCache.get('user1');
|
|
489
|
-
$.log.debug('加载的用户数据:', loadedUser);
|
|
490
|
-
|
|
491
|
-
// 销毁实例时,会自动保存数据
|
|
492
|
-
await userCache.dispose();
|
|
493
|
-
await productCache.dispose();
|
|
494
|
-
}
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
### 批量操作示例
|
|
498
|
-
```javascript
|
|
499
|
-
async function batchExample() {
|
|
500
|
-
// 批量设置
|
|
501
|
-
await cache.mset(["key1", "key2", "key3"], ["value1", "value2", "value3"]);
|
|
502
|
-
|
|
503
|
-
// 批量获取
|
|
504
|
-
const values = await cache.mget("key1", "key2", "key3");
|
|
505
|
-
$.log.debug("批量获取:", values); // 输出: ["value1", "value2", "value3"]
|
|
506
|
-
|
|
507
|
-
// 检查多个键是否存在
|
|
508
|
-
const existsCount = await cache.exists("key1", "key2", "nonexistent");
|
|
509
|
-
$.log.debug("存在的键数量:", existsCount); // 输出: 2
|
|
510
|
-
|
|
511
|
-
// 获取键数量
|
|
512
|
-
const count = await cache.dbsize();
|
|
513
|
-
$.log.debug("键总数:", count);
|
|
514
|
-
|
|
515
|
-
// 清空所有缓存
|
|
516
|
-
await cache.flushdb();
|
|
517
|
-
}
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
## 注意事项
|
|
521
|
-
|
|
522
|
-
1. 所有操作方法都是异步的,需要使用async/await或Promise处理
|
|
523
|
-
2. 过期时间单位为秒,-1表示永不过期
|
|
524
|
-
3. 缓存数据默认存储在内存中,重启后数据会丢失
|
|
525
|
-
4. 启用持久化时,数据将保存到`{scope}.cache.json`文件,不同scope的数据存储在不同文件中,实现数据隔离
|
|
526
|
-
5. 缓存目录会在第一次使用时自动创建,无需手动创建
|
|
527
|
-
6. 事件回调函数中的 `cancel` 标志只在前置事件中有效,后置事件中修改不会产生效果
|
|
528
|
-
7. 所有事件参数都遵循统一的格式,包含key、value、result、error和cancel等字段
|
|
529
|
-
|
|
530
|
-
## 贡献指南
|
|
531
|
-
|
|
532
|
-
欢迎参与mm_cachebase项目的开发和改进!以下是贡献代码的基本步骤:
|
|
533
|
-
|
|
534
|
-
1. **Fork 仓库**:在Gitee上Fork项目到您的账户
|
|
535
|
-
2. **克隆仓库**:`git clone https://gitee.com/您的用户名/mm_cachebase.git`
|
|
536
|
-
3. **创建分支**:`git checkout -b feature/your-feature-name`
|
|
537
|
-
4. **提交更改**:`git commit -m "feat: 添加新功能描述"`
|
|
538
|
-
5. **推送分支**:`git push origin feature/your-feature-name`
|
|
539
|
-
6. **创建PR**:在Gitee上提交Pull Request
|
|
540
|
-
|
|
541
|
-
## 问题反馈
|
|
542
|
-
|
|
543
|
-
如果您在使用过程中遇到任何问题或有改进建议,请通过以下方式反馈:
|
|
544
|
-
|
|
545
|
-
- **Gitee Issues**:[https://gitee.com/qiuwenwu91/mm_cachebase/issues](https://gitee.com/qiuwenwu91/mm_cachebase/issues)
|
|
546
|
-
- **NPM 链接**:[https://www.npmjs.com/package/mm_cachebase](https://www.npmjs.com/package/mm_cachebase)
|
|
547
|
-
|
|
548
|
-
## 鸣谢
|
|
549
|
-
|
|
550
|
-
感谢所有为mm_cachebase项目做出贡献的开发者和用户!
|
|
551
|
-
|
|
552
|
-
## 相关链接
|
|
553
|
-
|
|
554
|
-
- **Node.js 官方文档**:[https://nodejs.org/docs/latest/api/](https://nodejs.org/docs/latest/api/)
|
|
555
|
-
- **Redis 命令参考**:[https://redis.io/commands/](https://redis.io/commands/)
|
|
556
|
-
|
|
557
|
-
## 许可证
|
|
558
|
-
|
|
559
|
-
MIT
|
|
1
|
+
# mm_cachebase
|
|
2
|
+
|
|
3
|
+
一个轻量级的本地缓存类库,提供与 **mm_redis 完全对齐** 的异步缓存操作接口,支持过期时间、哈希表、列表、集合、有序集合、发布订阅等功能,以及冒号风格的事件通知系统。
|
|
4
|
+
|
|
5
|
+
## 项目信息
|
|
6
|
+
|
|
7
|
+
- **当前版本**: 2.0.0
|
|
8
|
+
- **更新日期**: 2026-08-04
|
|
9
|
+
- **Gitee地址**: [https://gitee.com/qiuwenwu91/mm_cachebase](https://gitee.com/qiuwenwu91/mm_cachebase)
|
|
10
|
+
- **Node.js 版本要求**: >= 14.0.0(推荐 16.0.0 及以上)
|
|
11
|
+
|
|
12
|
+
## 特点
|
|
13
|
+
|
|
14
|
+
- **接口与 mm_redis 完全对齐**:全异步 API、冒号风格事件、统一方法签名与返回值,可与 mm_redis 无缝切换
|
|
15
|
+
- **全异步设计**:所有公共方法均为 `async`,返回 `Promise`
|
|
16
|
+
- **冒号风格事件**:`set:before` / `set:after` / `set:error`,与 mm_redis 一致
|
|
17
|
+
- **完整的数据类型支持**:字符串、哈希表、列表、集合、有序集合、发布订阅
|
|
18
|
+
- **过期时间管理**:支持秒级 `expire` 与毫秒级 `pexpire`
|
|
19
|
+
- **多文件持久化**:通过 `scope` 参数实现多实例数据隔离
|
|
20
|
+
|
|
21
|
+
## 安装
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install mm_cachebase
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 基本使用
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
const { CacheBase } = require('mm_cachebase');
|
|
31
|
+
|
|
32
|
+
// 创建缓存实例(构造时自动初始化)
|
|
33
|
+
const cache = new CacheBase({ scope: 'myapp' });
|
|
34
|
+
|
|
35
|
+
async function example() {
|
|
36
|
+
// 设置缓存,10 秒过期
|
|
37
|
+
await cache.set("name", "张三", 10);
|
|
38
|
+
|
|
39
|
+
// 获取缓存
|
|
40
|
+
const value = await cache.get("name");
|
|
41
|
+
$.log.debug(value); // 输出: 张三
|
|
42
|
+
|
|
43
|
+
// 删除缓存(返回删除数量)
|
|
44
|
+
const deleted = await cache.del("name");
|
|
45
|
+
$.log.debug(deleted); // 输出: 1
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 连接管理
|
|
50
|
+
|
|
51
|
+
与 mm_redis 一致的连接管理接口:
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
const cache = new CacheBase({ scope: 'myapp' });
|
|
55
|
+
await cache.init(); // 初始化(构造时已自动调用)
|
|
56
|
+
await cache.open(); // 打开连接(等同于 init)
|
|
57
|
+
const connected = cache.isConnected(); // 检查连接状态,返回 Boolean
|
|
58
|
+
await cache.close(); // 关闭连接(等同于 destroy)
|
|
59
|
+
cache.dispose(); // 同步销毁(清理定时器与数据)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## API 说明
|
|
63
|
+
|
|
64
|
+
所有方法均为 `async`,返回 `Promise`。事件名采用冒号风格(`xxx:before` / `xxx:after` / `xxx:error`)。
|
|
65
|
+
|
|
66
|
+
### 键值操作
|
|
67
|
+
|
|
68
|
+
| 方法 | 签名 | 返回值 |
|
|
69
|
+
|------|------|--------|
|
|
70
|
+
| set | `set(key, value, seconds=0)` | `Promise<Boolean>` |
|
|
71
|
+
| get | `get(key)` | `Promise<Object\|null>` |
|
|
72
|
+
| del | `del(key)` | `Promise<Number>` 删除数量 |
|
|
73
|
+
| exists | `exists(key)` | `Promise<Number>` 0/1 |
|
|
74
|
+
| has | `has(key)` | `Promise<Boolean>` |
|
|
75
|
+
| getset | `getset(key, value, seconds=0)` | `Promise<Object\|null>` 旧值 |
|
|
76
|
+
| add | `add(key, value, seconds=0)` | `Promise<Boolean>` SETNX 语义 |
|
|
77
|
+
|
|
78
|
+
### 批量操作
|
|
79
|
+
|
|
80
|
+
| 方法 | 签名 | 返回值 |
|
|
81
|
+
|------|------|--------|
|
|
82
|
+
| mset | `mset(obj, seconds=0)` | `Promise<Boolean>` |
|
|
83
|
+
| mget | `mget(keys)` | `Promise<Array>` |
|
|
84
|
+
|
|
85
|
+
### 过期时间管理
|
|
86
|
+
|
|
87
|
+
| 方法 | 签名 | 返回值 |
|
|
88
|
+
|------|------|--------|
|
|
89
|
+
| expire | `expire(key, seconds)` | `Promise<Boolean>` |
|
|
90
|
+
| pexpire | `pexpire(key, milliseconds)` | `Promise<Boolean>` |
|
|
91
|
+
| persist | `persist(key)` | `Promise<Boolean>` |
|
|
92
|
+
| ttl | `ttl(key, [seconds])` | `Promise<Number\|Boolean>` |
|
|
93
|
+
|
|
94
|
+
### 哈希表操作
|
|
95
|
+
|
|
96
|
+
| 方法 | 签名 | 返回值 |
|
|
97
|
+
|------|------|--------|
|
|
98
|
+
| hset | `hset(key, field, value)` | `Promise<Boolean>` |
|
|
99
|
+
| hget | `hget(key, field)` | `Promise<Object\|null>` |
|
|
100
|
+
| hgetall | `hgetall(key)` | `Promise<Object>` |
|
|
101
|
+
| hdel | `hdel(key, field)` | `Promise<Number>` 删除字段数 |
|
|
102
|
+
| hmset | `hmset(key, obj)` | `Promise<Boolean>` |
|
|
103
|
+
| hmget | `hmget(key, fields)` | `Promise<Array>` |
|
|
104
|
+
| hlen | `hlen(key)` | `Promise<Number>` |
|
|
105
|
+
|
|
106
|
+
### 数值操作
|
|
107
|
+
|
|
108
|
+
| 方法 | 签名 | 返回值 |
|
|
109
|
+
|------|------|--------|
|
|
110
|
+
| incr | `incr(key, seconds=0)` | `Promise<Number>` 错误返回 null |
|
|
111
|
+
| decr | `decr(key, seconds=0)` | `Promise<Number>` 错误返回 null |
|
|
112
|
+
| incrby | `incrby(key, increment, seconds=0)` | `Promise<Number>` 错误返回 null |
|
|
113
|
+
| decrby | `decrby(key, decrement, seconds=0)` | `Promise<Number>` 错误返回 null |
|
|
114
|
+
| incrbyfloat | `incrbyfloat(key, increment, seconds=0)` | `Promise<Number>` 错误返回 null |
|
|
115
|
+
| addInt | `addInt(key, value, seconds=0)` | `Promise<Number>` 兼容方法 |
|
|
116
|
+
| addFloat | `addFloat(key, num, seconds=0)` | `Promise<Number>` 兼容方法 |
|
|
117
|
+
|
|
118
|
+
### 字符串操作
|
|
119
|
+
|
|
120
|
+
| 方法 | 签名 | 返回值 |
|
|
121
|
+
|------|------|--------|
|
|
122
|
+
| setrange | `setrange(key, value, seconds=0)` | `Promise<Number>` 追加后长度 |
|
|
123
|
+
| append | `append(key, value)` | `Promise<Number>` 长度 |
|
|
124
|
+
| strlen | `strlen(key)` | `Promise<Number>` |
|
|
125
|
+
|
|
126
|
+
### 列表操作
|
|
127
|
+
|
|
128
|
+
| 方法 | 签名 | 返回值 |
|
|
129
|
+
|------|------|--------|
|
|
130
|
+
| setForList | `setForList(key, value, seconds=0)` | `Promise<Number>` 列表长度 |
|
|
131
|
+
| addForList | `addForList(key, value, seconds=0)` | `Promise<Number>` 列表长度 |
|
|
132
|
+
| getForList | `getForList(key, start=0, end=-1)` | `Promise<Array>` |
|
|
133
|
+
| hasForList | `hasForList(key, value)` | `Promise<Boolean>` |
|
|
134
|
+
| clearForList | `clearForList(key)` | `Promise<Boolean>` |
|
|
135
|
+
|
|
136
|
+
### 集合操作
|
|
137
|
+
|
|
138
|
+
| 方法 | 签名 | 返回值 |
|
|
139
|
+
|------|------|--------|
|
|
140
|
+
| sadd | `sadd(key, members)` | `Promise<Number>` 添加数量 |
|
|
141
|
+
| srem | `srem(key, members)` | `Promise<Number>` 移除数量 |
|
|
142
|
+
| sismember | `sismember(key, member)` | `Promise<Boolean>` |
|
|
143
|
+
| smembers | `smembers(key)` | `Promise<Array>` |
|
|
144
|
+
| scard | `scard(key)` | `Promise<Number>` |
|
|
145
|
+
| sinter | `sinter(...keys)` | `Promise<Array>` 交集 |
|
|
146
|
+
| sunion | `sunion(...keys)` | `Promise<Array>` 并集 |
|
|
147
|
+
| sdiff | `sdiff(...keys)` | `Promise<Array>` 差集 |
|
|
148
|
+
|
|
149
|
+
### 有序集合操作
|
|
150
|
+
|
|
151
|
+
| 方法 | 签名 | 返回值 |
|
|
152
|
+
|------|------|--------|
|
|
153
|
+
| zadd | `zadd(key, score, member)` | `Promise<Boolean>` 新成员返回 true |
|
|
154
|
+
| zrem | `zrem(key, members)` | `Promise<Number>` 移除数量 |
|
|
155
|
+
| zscore | `zscore(key, member)` | `Promise<Number\|null>` |
|
|
156
|
+
| zrank | `zrank(key, member)` | `Promise<Number\|null>` |
|
|
157
|
+
| zrange | `zrange(key, start, stop, withScores=false)` | `Promise<Array>` |
|
|
158
|
+
| zcard | `zcard(key)` | `Promise<Number>` |
|
|
159
|
+
| zincrby | `zincrby(key, increment, member)` | `Promise<Number>` |
|
|
160
|
+
|
|
161
|
+
### 发布订阅
|
|
162
|
+
|
|
163
|
+
> **注意**:发布订阅为进程内实现,无跨进程能力,与 mm_redis 的跨进程语义不同。
|
|
164
|
+
|
|
165
|
+
| 方法 | 签名 | 返回值 |
|
|
166
|
+
|------|------|--------|
|
|
167
|
+
| subscribe | `subscribe(channel, func)` | `Promise<Boolean>` |
|
|
168
|
+
| unsubscribe | `unsubscribe(channel)` | `Promise<Boolean>` |
|
|
169
|
+
| publish | `publish(channel, message)` | `Promise<Number>` 接收者数量 |
|
|
170
|
+
|
|
171
|
+
### 键管理
|
|
172
|
+
|
|
173
|
+
| 方法 | 签名 | 返回值 |
|
|
174
|
+
|------|------|--------|
|
|
175
|
+
| keys | `keys(pattern)` | `Promise<Array>` 支持 `*` 通配符 |
|
|
176
|
+
| dbsize | `dbsize()` | `Promise<Number>` |
|
|
177
|
+
| flushdb | `flushdb()` | `Promise<Boolean>` |
|
|
178
|
+
| clear | `clear()` | `Promise<Boolean>` flushdb 别名 |
|
|
179
|
+
|
|
180
|
+
## 事件系统
|
|
181
|
+
|
|
182
|
+
事件名采用**冒号风格**,与 mm_redis 完全一致。每个操作有 `:before`、`:after`、`:error` 三种事件。
|
|
183
|
+
|
|
184
|
+
```javascript
|
|
185
|
+
const cache = new CacheBase({ scope: 'myapp' });
|
|
186
|
+
|
|
187
|
+
// 监听 set 前置事件,可修改参数或取消操作
|
|
188
|
+
cache.on('set:before', (ctx) => {
|
|
189
|
+
$.log.debug('即将设置键:', ctx.key, '值:', ctx.value);
|
|
190
|
+
// 可修改 ctx.key / ctx.value / ctx.seconds
|
|
191
|
+
// 设置 ctx.cancel = true 可取消操作
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// 监听 set 后置事件
|
|
195
|
+
cache.on('set:after', (data) => {
|
|
196
|
+
$.log.debug('设置完成:', data.key, '成功:', data.success);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// 监听错误事件
|
|
200
|
+
cache.on('set:error', (data) => {
|
|
201
|
+
$.log.error('设置出错:', data.key, data.error);
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### 支持的事件
|
|
206
|
+
|
|
207
|
+
所有公共方法均有对应事件,命名规则为 `方法名:before` / `方法名:after` / `方法名:error`:
|
|
208
|
+
|
|
209
|
+
- 键值:`set`、`get`、`del`、`exists`、`add`
|
|
210
|
+
- 批量:`mset`、`mget`
|
|
211
|
+
- 过期:`expire`、`pexpire`、`persist`、`ttl`
|
|
212
|
+
- 哈希:`hset`、`hget`、`hgetall`、`hdel`、`hmset`、`hmget`、`hlen`
|
|
213
|
+
- 数值:`incr`、`decr`、`incrby`、`decrby`、`incrbyfloat`、`addInt`、`addFloat`
|
|
214
|
+
- 字符串:`setrange`、`append`
|
|
215
|
+
- 列表:`setForList`、`addForList`、`getForList`、`hasForList`、`clearForList`
|
|
216
|
+
- 集合:`sadd`、`srem`、`sismember`、`smembers`
|
|
217
|
+
- 有序集合:`zadd`、`zrem`
|
|
218
|
+
- 键管理:`keys`、`clear`
|
|
219
|
+
|
|
220
|
+
## 使用示例
|
|
221
|
+
|
|
222
|
+
### 集合操作
|
|
223
|
+
|
|
224
|
+
```javascript
|
|
225
|
+
async function setExample() {
|
|
226
|
+
await cache.sadd('tags', ['node', 'js', 'cache']);
|
|
227
|
+
const isMember = await cache.sismember('tags', 'node'); // true
|
|
228
|
+
const members = await cache.smembers('tags'); // ['node', 'js', 'cache']
|
|
229
|
+
const count = await cache.scard('tags'); // 3
|
|
230
|
+
await cache.srem('tags', ['js']);
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 有序集合操作
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
async function zsetExample() {
|
|
238
|
+
await cache.zadd('ranking', 100, 'user1');
|
|
239
|
+
await cache.zadd('ranking', 200, 'user2');
|
|
240
|
+
const rank = await cache.zrank('ranking', 'user1'); // 0
|
|
241
|
+
const top = await cache.zrange('ranking', 0, -1, true); // [{member:'user1', score:100}, ...]
|
|
242
|
+
await cache.zincrby('ranking', 50, 'user1'); // 新分数 150
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### 发布订阅
|
|
247
|
+
|
|
248
|
+
```javascript
|
|
249
|
+
async function pubsubExample() {
|
|
250
|
+
await cache.subscribe('news', (message) => {
|
|
251
|
+
$.log.debug('收到消息:', message);
|
|
252
|
+
});
|
|
253
|
+
await cache.publish('news', 'hello world'); // 接收者数量: 1
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## 与 mm_redis 的接口一致性
|
|
258
|
+
|
|
259
|
+
本模块与 [mm_redis](../mm_redis) 提供完全对齐的接口,调用方可通过统一的方式使用内存缓存或 Redis 缓存:
|
|
260
|
+
|
|
261
|
+
- **全异步**:所有方法返回 `Promise`
|
|
262
|
+
- **事件命名**:冒号风格 `xxx:before` / `xxx:after` / `xxx:error`
|
|
263
|
+
- **方法签名**:`set(key, value, seconds=0)`、`mset(obj, seconds=0)`、`incrby(key, increment, seconds=0)` 等
|
|
264
|
+
- **返回值**:`hset` 返回 `Boolean`,`del`/`exists`/`hdel` 返回 `Number`,`hget` 不存在返回 `null`
|
|
265
|
+
|
|
266
|
+
**差异点**:
|
|
267
|
+
- 发布订阅为进程内实现(mm_redis 支持跨进程)
|
|
268
|
+
- 集合/有序集合用 JS 原生 `Set`/`Map` 实现,无 Redis 的 O(log N) 复杂度保证
|
|
269
|
+
- 构造函数自动初始化(内存缓存特性),mm_redis 需显式 `open()`
|