mm_redis 2.0.8 → 2.0.9

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.
Files changed (4) hide show
  1. package/README.md +102 -38
  2. package/README_EN.md +433 -0
  3. package/index.js +63 -115
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -1,22 +1,28 @@
1
1
  # mm_redis
2
2
 
3
- mm_redis是一个高效的Redis客户端封装库,提供了全面的Redis功能支持,包括连接池管理、数据类型操作、错误处理和批量操作优化。
4
-
5
- [![npm version](https://badge.fury.io/js/mm_redis.svg)](https://badge.fury.io/js/mm_redis)
3
+ [![npm version](https://badge.fury.io/js/mm_redis.svg)](https://www.npmjs.com/package/mm_redis)
6
4
  [![npm downloads](https://img.shields.io/npm/dm/mm_redis.svg)](https://www.npmjs.com/package/mm_redis)
5
+ [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
6
+
7
+ > 一个高效的Redis客户端封装库,提供完整的连接池管理、数据类型操作和批量操作优化
7
8
 
8
9
  ## 版本信息
9
10
 
11
+ - **最新版本**: 2.0.0
10
12
  - **更新日期**: 2025-10-20
11
13
  - **作者**: qww
12
14
  - **NPM**: [https://www.npmjs.com/package/mm_redis](https://www.npmjs.com/package/mm_redis)
13
15
  - **GitHub**: [https://gitee.com/qiuwenwu91/mm_redis](https://gitee.com/qiuwenwu91/mm_redis)
16
+ - **Node.js**: >= 14.0.0
14
17
 
15
18
  ## 功能特性
16
19
 
20
+ ### 🚀 核心功能
17
21
  - **完整的连接池管理**:优化并发性能,支持连接复用和自动回收
18
22
  - **Pipeline批量操作**:支持Redis Pipeline机制,大幅提升批量操作效率
19
23
  - **全面的数据类型支持**:覆盖String、List、Hash、Set、Sorted Set等所有主要Redis数据类型
24
+
25
+ ### 🔧 高级特性
20
26
  - **智能连接管理**:自动重连机制,使用指数退避策略,确保连接稳定可靠
21
27
  - **健壮的错误处理**:全面的错误处理机制和详细的日志记录,便于问题排查
22
28
  - **便捷的数据序列化**:自动JSON序列化/反序列化,无需手动转换数据格式
@@ -26,55 +32,113 @@ mm_redis是一个高效的Redis客户端封装库,提供了全面的Redis功
26
32
 
27
33
  ## 安装
28
34
 
35
+ ### npm
36
+ ```bash
37
+ npm install mm_redis
38
+ ```
39
+
40
+ ### yarn
41
+ ```bash
42
+ yarn add mm_redis
43
+ ```
44
+
45
+ ### pnpm
29
46
  ```bash
30
- npm install mm_redis --save
47
+ pnpm add mm_redis
31
48
  ```
32
49
 
33
- ## Node.js版本要求
50
+ ## 快速开始
51
+
52
+ ```javascript
53
+ const { Redis } = require('mm_redis');
54
+
55
+ // 创建Redis实例
56
+ const redis = new Redis({
57
+ host: 'localhost',
58
+ port: 6379,
59
+ password: 'your_password',
60
+ db: 0
61
+ });
62
+
63
+ // 连接Redis
64
+ await redis.connect();
65
+
66
+ // 设置缓存
67
+ await redis.set('user:1', { name: '张三', age: 25 });
68
+
69
+ // 获取缓存
70
+ const user = await redis.get('user:1');
71
+ console.log(user); // { name: '张三', age: 25 }
34
72
 
35
- - **最低支持版本**:Node.js 14.0.0
36
- - **推荐版本**:Node.js 16.0.0及以上
73
+ // 错误处理
74
+ try {
75
+ await redis.set('key', 'value');
76
+ } catch (err) {
77
+ console.error('Redis操作失败:', err);
78
+ }
79
+ ```
37
80
 
38
81
  ## 配置引入方式
39
82
 
40
- mm_redis支持多种配置引入方式:
83
+ mm_redis支持多种配置引入方式,满足不同场景的需求:
41
84
 
42
- 1. **对象配置(推荐)**:直接传入配置对象
85
+ ### 1. 对象配置(推荐)
43
86
  ```javascript
44
- const Redis = require('mm_redis');
45
- const redis = new Redis('default');
46
- redis.setConfig({
47
- // 服务器地址
48
- host: "localhost",
49
- // 端口号
87
+ const { Redis } = require('mm_redis');
88
+
89
+ // 直接传入配置对象
90
+ const redis = new Redis({
91
+ host: 'localhost',
50
92
  port: 6379,
51
- // 密码
52
- password: "",
53
- // 数据库
54
- database: 0,
55
- // 前缀
56
- prefix: "app:",
57
- // 连接超时时间(ms)
58
- connect_timeout: 10000,
59
- // 重试次数
60
- retry_count: 3,
61
- // 重试间隔(ms)
62
- retry_delay: 1000,
63
- // 连接池配置
64
- pool: {
65
- max_clients: 10, // 最大连接数
66
- min_idle: 2, // 最小空闲连接数
67
- max_idle: 5, // 最大空闲连接数
68
- idle_timeout: 30000 // 空闲超时时间(ms)
69
- }
93
+ password: 'your_password',
94
+ db: 0,
95
+ key_prefix: 'app:',
96
+ max_clients: 10,
97
+ connect_timeout: 5000
70
98
  });
71
99
  ```
72
100
 
73
- 2. **文件配置**:传入配置文件路径
101
+ ### 2. 文件配置
102
+ ```javascript
103
+ // config/redis.json
104
+ {
105
+ "host": "localhost",
106
+ "port": 6379,
107
+ "password": "your_password",
108
+ "db": 0,
109
+ "key_prefix": "app:",
110
+ "max_clients": 10,
111
+ "connect_timeout": 5000
112
+ }
113
+
114
+ // 使用配置
115
+ const { Redis } = require('mm_redis');
116
+ const config = require('./config/redis.json');
117
+ const redis = new Redis(config);
118
+ ```
119
+
120
+ ### 3. 环境变量配置
74
121
  ```javascript
75
- const Redis = require('mm_redis');
76
- const redis = new Redis('default');
77
- redis.setConfig('./config.json');
122
+ // 环境变量
123
+ REDIS_HOST=localhost
124
+ REDIS_PORT=6379
125
+ REDIS_PASSWORD=your_password
126
+ REDIS_DB=0
127
+ REDIS_KEY_PREFIX=app:
128
+ REDIS_MAX_CLIENTS=10
129
+ REDIS_CONNECT_TIMEOUT=5000
130
+
131
+ // 使用环境变量
132
+ const { Redis } = require('mm_redis');
133
+ const redis = new Redis({
134
+ host: process.env.REDIS_HOST,
135
+ port: parseInt(process.env.REDIS_PORT),
136
+ password: process.env.REDIS_PASSWORD,
137
+ db: parseInt(process.env.REDIS_DB),
138
+ key_prefix: process.env.REDIS_KEY_PREFIX,
139
+ max_clients: parseInt(process.env.REDIS_MAX_CLIENTS),
140
+ connect_timeout: parseInt(process.env.REDIS_CONNECT_TIMEOUT)
141
+ });
78
142
  ```
79
143
  ## 变更日志
80
144
 
package/README_EN.md ADDED
@@ -0,0 +1,433 @@
1
+ # mm_redis
2
+
3
+ [![npm version](https://badge.fury.io/js/mm_redis.svg)](https://www.npmjs.com/package/mm_redis)
4
+ [![npm downloads](https://img.shields.io/npm/dm/mm_redis.svg)](https://www.npmjs.com/package/mm_redis)
5
+ [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
6
+
7
+ A high-performance Redis client wrapper library that provides comprehensive Redis functionality support, including connection pool management, data type operations, error handling, and batch operation optimization.
8
+
9
+ ## Version Information
10
+
11
+ - **Latest Version**: 2.0.0
12
+ - **Update Date**: 2025-10-20
13
+ - **Author**: qww
14
+ - **NPM**: [https://www.npmjs.com/package/mm_redis](https://www.npmjs.com/package/mm_redis)
15
+ - **GitHub**: [https://gitee.com/qiuwenwu91/mm_redis](https://gitee.com/qiuwenwu91/mm_redis)
16
+ - **Node.js**: >= 14.0.0
17
+
18
+ ## Features
19
+
20
+ ### 🚀 Core Features
21
+ - **Complete Connection Pool Management**: Optimized concurrent performance with connection reuse and automatic recycling
22
+ - **Pipeline Batch Operations**: Support for Redis Pipeline mechanism, significantly improving batch operation efficiency
23
+ - **Comprehensive Data Type Support**: Covers all major Redis data types including String, List, Hash, Set, Sorted Set
24
+
25
+ ### 🔧 Advanced Features
26
+ - **Smart Connection Management**: Automatic reconnection with exponential backoff strategy for reliable connections
27
+ - **Robust Error Handling**: Comprehensive error handling mechanism with detailed logging
28
+ - **Automatic Data Serialization**: Automatic JSON serialization/deserialization without manual conversion
29
+ - **Key Space Isolation**: Support for key prefix management for multi-business scenario data isolation
30
+ - **Flexible Event System**: Unified event mechanism supporting pre/post operation event listening and interception
31
+ - **Rich Numeric Operations**: Support for atomic increment/decrement operations, suitable for counter scenarios
32
+
33
+ ## Installation
34
+
35
+ ### Using npm
36
+ ```bash
37
+ npm install mm_redis --save
38
+ ```
39
+
40
+ ### Using yarn
41
+ ```bash
42
+ yarn add mm_redis
43
+ ```
44
+
45
+ ### Using pnpm
46
+ ```bash
47
+ pnpm add mm_redis
48
+ ```
49
+
50
+ ## Node.js Version Requirements
51
+
52
+ - **Minimum Supported Version**: Node.js 14.0.0
53
+ - **Recommended Version**: Node.js 16.0.0 and above
54
+
55
+ ## Quick Start
56
+
57
+ ### Basic Usage
58
+ ```javascript
59
+ const Redis = require('mm_redis');
60
+
61
+ // Create Redis instance
62
+ const redis = new Redis('default');
63
+
64
+ async function example() {
65
+ try {
66
+ // Connect to Redis
67
+ await redis.open();
68
+
69
+ // Set cache with expiration
70
+ await redis.set('user:1', { name: 'John', age: 25 }, 3600);
71
+
72
+ // Get cache
73
+ const user = await redis.get('user:1');
74
+ console.log('User info:', user);
75
+
76
+ // Close connection
77
+ await redis.close();
78
+ } catch (error) {
79
+ console.error('Operation failed:', error);
80
+ }
81
+ }
82
+
83
+ example();
84
+ ```
85
+
86
+ ## Configuration
87
+
88
+ mm_redis supports multiple configuration loading methods:
89
+
90
+ ### Object Configuration (Recommended)
91
+ ```javascript
92
+ const Redis = require('mm_redis');
93
+ const redis = new Redis('default');
94
+
95
+ redis.setConfig({
96
+ host: "localhost",
97
+ port: 6379,
98
+ password: "",
99
+ database: 0,
100
+ prefix: "app:",
101
+ connect_timeout: 10000,
102
+ retry_count: 3,
103
+ retry_delay: 1000,
104
+ pool: {
105
+ max_clients: 10,
106
+ min_idle: 2,
107
+ max_idle: 5,
108
+ idle_timeout: 30000
109
+ }
110
+ });
111
+ ```
112
+
113
+ ### File Configuration
114
+ ```javascript
115
+ const Redis = require('mm_redis');
116
+ const redis = new Redis('default');
117
+
118
+ redis.setConfig('./config.json');
119
+ ```
120
+
121
+ Configuration file example (`config.json`):
122
+ ```json
123
+ {
124
+ "host": "localhost",
125
+ "port": 6379,
126
+ "password": "",
127
+ "database": 0,
128
+ "prefix": "app:",
129
+ "connect_timeout": 10000,
130
+ "retry_count": 3,
131
+ "retry_delay": 1000,
132
+ "pool": {
133
+ "max_clients": 10,
134
+ "min_idle": 2,
135
+ "max_idle": 5,
136
+ "idle_timeout": 30000
137
+ }
138
+ }
139
+ ```
140
+
141
+ ### Environment Variables
142
+ ```javascript
143
+ const Redis = require('mm_redis');
144
+ const redis = new Redis('default');
145
+
146
+ redis.setConfig({
147
+ host: process.env.REDIS_HOST || 'localhost',
148
+ port: parseInt(process.env.REDIS_PORT) || 6379,
149
+ password: process.env.REDIS_PASSWORD || '',
150
+ database: parseInt(process.env.REDIS_DB) || 0
151
+ });
152
+ ```
153
+
154
+ ## Change Log
155
+
156
+ ### v2.0.0 (2025-10-14)
157
+ - Removed list_push method, unified to use addForList method for list operations
158
+ - Updated documentation, replaced all list_push references with addForList
159
+ - Updated API list and usage examples in documentation
160
+ - Optimized connection pool configuration management, unified configuration to this.config.pool
161
+ - Added connection pool configuration parameters: min_idle, max_idle, idle_timeout
162
+
163
+ ### v1.9.8 (2024-12-22)
164
+ - Updated documentation, improved content required for npm publishing
165
+ - Added GitHub repository link to documentation
166
+ - Optimized feature description, enhanced document readability
167
+ - Added Node.js version requirement description
168
+
169
+ ### v1.9.5 (2024-12-21)
170
+ - Fixed compatibility issues with hmset and hgetall methods to ensure compatibility with Redis client v5
171
+ - Removed deprecated hexists, hkeys and hvals methods, optimized API design
172
+ - Optimized implementation of mget and mset methods to ensure full compatibility with Redis v5 API
173
+ - Updated test scripts, removed calls to deprecated methods
174
+ - Updated compatibility table to ensure documentation matches actual API
175
+ - Fixed errors in native Redis API calls, improved code stability
176
+ - Optimized connection pool management, fixed potential memory leak issues
177
+
178
+ ### v1.9.4 (2024-12-20)
179
+ - Optimized configuration loading methods, supporting both object configuration and file path configuration
180
+ - Improved implementation of setConfig method, using Object.assign instead of original merge method
181
+ - Fixed warning messages related to connection pool
182
+ - Enhanced error handling mechanism
183
+
184
+ ### v1.9.0 (2024-11-20)
185
+ - Initial version release
186
+ - Support for complete connection pool management
187
+ - Implementation of Pipeline batch operations
188
+ - Support for all major Redis data type operations
189
+
190
+ ## Usage Examples
191
+
192
+ ### Basic Operations
193
+ ```javascript
194
+ // Connect to Redis
195
+ await redis.open();
196
+
197
+ // Set cache
198
+ await redis.set('user:1', { name: 'John', age: 25 }, 3600);
199
+
200
+ // Get cache
201
+ const user = await redis.get('user:1');
202
+ console.log('User info:', user);
203
+
204
+ // Check if key exists
205
+ const exists = await redis.has('user:1');
206
+
207
+ // Delete cache
208
+ await redis.del('user:1');
209
+
210
+ // Close connection
211
+ await redis.close();
212
+ ```
213
+
214
+ ### List Operations
215
+ ```javascript
216
+ // Set list
217
+ await redis.setForList('users', ['user1', 'user2', 'user3']);
218
+
219
+ // Add element to list
220
+ await redis.addForList('users', 'user4');
221
+
222
+ // Get list
223
+ const users = await redis.getForList('users');
224
+ console.log('User list:', users);
225
+
226
+ // Get partial list elements
227
+ const partialUsers = await redis.getForList('users', 0, 2);
228
+
229
+ // Clear list
230
+ await redis.clearForList('users');
231
+ ```
232
+
233
+ ### Hash Operations
234
+ ```javascript
235
+ // Set hash field
236
+ await redis.hset('user:profile:1', 'name', 'John');
237
+ await redis.hset('user:profile:1', 'age', 25);
238
+
239
+ // Batch set hash fields
240
+ await redis.hmset('user:profile:1', {
241
+ 'email': 'john@example.com',
242
+ 'phone': '1234567890'
243
+ });
244
+
245
+ // Get hash field
246
+ const name = await redis.hget('user:profile:1', 'name');
247
+
248
+ // Get all hash fields and values
249
+ const profile = await redis.hgetall('user:profile:1');
250
+ console.log('User profile:', profile);
251
+
252
+ // Get hash field count
253
+ const fieldCount = await redis.hlen('user:profile:1');
254
+
255
+ // Delete hash fields
256
+ await redis.hdel('user:profile:1', ['email', 'phone']);
257
+ ```
258
+
259
+ ### Batch Operations
260
+ ```javascript
261
+ // Batch get
262
+ const data = await redis.mget(['user:1', 'user:2', 'user:3']);
263
+ console.log('Batch get result:', data);
264
+
265
+ // Batch set
266
+ await redis.mset({
267
+ 'user:4': { name: 'Jane', age: 30 },
268
+ 'user:5': { name: 'Bob', age: 35 }
269
+ }, 3600);
270
+ ```
271
+
272
+ ### Pipeline Optimization
273
+ ```javascript
274
+ // Create Pipeline
275
+ const pipeline = redis.pipeline();
276
+
277
+ // Add multiple commands
278
+ pipeline.set('counter:1', 100);
279
+ pipeline.ttl('counter:1', 3600);
280
+ pipeline.hset('stats:today', 'visits', 500);
281
+ pipeline.hset('stats:today', 'users', 100);
282
+
283
+ // Execute all commands
284
+ const results = await pipeline.exec();
285
+ console.log('Pipeline execution result:', results);
286
+ ```
287
+
288
+ ### Publish/Subscribe
289
+ ```javascript
290
+ // Subscribe to channel
291
+ await redis.subscribe('notifications', async (message) => {
292
+ console.log('Received notification:', message);
293
+ // Process received message
294
+ });
295
+
296
+ // Publish message
297
+ const receivedCount = await redis.publish('notifications', JSON.stringify({
298
+ type: 'info',
299
+ content: 'System update successful'
300
+ }));
301
+
302
+ console.log(`Message published, ${receivedCount} clients received`);
303
+
304
+ // Unsubscribe
305
+ await redis.unsubscribe('notifications');
306
+ ```
307
+
308
+ ## API Documentation
309
+
310
+ ### Connection Management
311
+ - `setConfig(config)`: Set Redis configuration
312
+ - `open()`: Connect to Redis
313
+ - `close()`: Close connection
314
+ - `isConnected()`: Check connection status
315
+
316
+ ### String Operations
317
+ - `set(key, value, seconds)`: Set cache
318
+ - `get(key)`: Get cache
319
+ - `has(key)`: Check if key exists
320
+ - `del(key)`: Delete cache
321
+ - `add(key, value, seconds)`: Set cache only if key doesn't exist
322
+ - `ttl(key, seconds)`: Set or get expiration time
323
+ - `addInt(key, num)`: Increment integer value
324
+ - `addFloat(key, num)`: Increment float value
325
+ - `addStr(key, str)`: Append string
326
+ - `getrange(key, start, end)`: Get substring
327
+ - `setrange(key, index, value)`: Set substring
328
+
329
+ ### List Operations
330
+ - `setForList(key, value, seconds)`: Set list
331
+ - `addForList(key, value)`: Add element to list
332
+ - `getForList(key, start, end)`: Get list
333
+ - `hasForList(key, value)`: Check if element exists in list
334
+ - `clearForList(key, value)`: Clear list or reset list
335
+
336
+ ### Hash Operations
337
+ - `hset(key, field, value)`: Set hash field
338
+ - `hmset(key, obj)`: Batch set hash fields
339
+ - `hget(key, field)`: Get hash field value
340
+ - `hgetall(key)`: Get all hash fields and values
341
+ - `hdel(key, fields)`: Delete hash fields
342
+ - `hlen(key)`: Get hash field count
343
+
344
+ ### Batch Operations
345
+ - `mget(keys)`: Batch get cache
346
+ - `mset(obj, seconds)`: Batch set cache
347
+ - `pipeline()`: Create Pipeline object for batch operation optimization
348
+
349
+ ### Set Operations
350
+ - `sadd(key, members)`: Add members to set
351
+ - `srem(key, members)`: Remove members from set
352
+ - `sismember(key, member)`: Check if member is in set
353
+ - `smembers(key)`: Get all members in set
354
+ - `scard(key)`: Get member count in set
355
+ - `sinter(keys)`: Get intersection of multiple sets
356
+ - `sunion(keys)`: Get union of multiple sets
357
+ - `sdiff(keys)`: Get difference of multiple sets
358
+
359
+ ### Sorted Set Operations
360
+ - `zadd(key, score, member)`: Add member to sorted set
361
+ - `zrem(key, members)`: Remove members from sorted set
362
+ - `zscore(key, member)`: Get member score in sorted set
363
+ - `zrank(key, member)`: Get member rank in sorted set
364
+ - `zrange(key, start, stop, withScores)`: Get members in specified range
365
+ - `zcard(key)`: Get member count in sorted set
366
+ - `zincrby(key, increment, member)`: Increment member score in sorted set
367
+
368
+ ### Numeric Operations
369
+ - `incr(key)`: Increment key value by 1
370
+ - `decr(key)`: Decrement key value by 1
371
+ - `incrby(key, increment)`: Increment key value by specified integer
372
+ - `decrby(key, decrement)`: Decrement key value by specified integer
373
+ - `expire(key, seconds)`: Set key expiration time
374
+
375
+ ## Connection Pool Management
376
+
377
+ This module has built-in efficient connection pool management that automatically handles connection creation, recycling, and reuse. Connection pool configuration can be set during initialization:
378
+
379
+ ```javascript
380
+ {
381
+ "pool": {
382
+ "max_clients": 10, // Maximum connections
383
+ "min_idle": 2, // Minimum idle connections
384
+ "max_idle": 5, // Maximum idle connections
385
+ "idle_timeout": 30000 // Idle timeout (ms)
386
+ }
387
+ }
388
+ ```
389
+
390
+ ## Error Handling
391
+
392
+ All methods include comprehensive error handling mechanisms and provide detailed log output. When errors occur, error information is automatically recorded and fallback solutions are provided when possible.
393
+
394
+ ## Best Practices
395
+
396
+ 1. **Use Connection Pool**: For high-concurrency applications, connection pool configuration is crucial. Reasonably set maximum connections and idle connections.
397
+ 2. **Use Pipeline**: For batch operations, using Pipeline can significantly improve performance.
398
+ 3. **Set Expiration Time Reasonably**: Avoid unlimited growth of data in Redis.
399
+ 4. **Use Key Prefix**: Isolate business through key prefix to avoid key conflicts.
400
+ 5. **Close Connections Timely**: Call close() method to close all connections when application ends.
401
+ 6. **Leverage Event System**: Use event system for logging, data validation, and operation interception.
402
+
403
+ ## Contributing
404
+
405
+ We welcome community contributions! If you're interested in contributing to the mm_redis project, please follow these steps:
406
+
407
+ 1. Fork this repository
408
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
409
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
410
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
411
+ 5. Open a Pull Request
412
+
413
+ Please ensure your code follows the project's coding standards and passes all tests.
414
+
415
+ ## License
416
+
417
+ This project is licensed under the ISC License - see the [LICENSE](LICENSE) file for details.
418
+
419
+ ## Issue Reporting
420
+
421
+ If you encounter any problems or have any suggestions during use, please provide feedback through the following methods:
422
+
423
+ - **GitHub Issues**: [https://gitee.com/qiuwenwu91/mm_redis/issues](https://gitee.com/qiuwenwu91/mm_redis/issues)
424
+ - **NPM**: [https://www.npmjs.com/package/mm_redis](https://www.npmjs.com/package/mm_redis)
425
+
426
+ ## Acknowledgments
427
+
428
+ Thanks to all developers and users who have contributed to this project!
429
+
430
+ ## Related Links
431
+
432
+ - **Redis Official Documentation**: [https://redis.io/documentation](https://redis.io/documentation)
433
+ - **Node Redis Client**: [https://github.com/redis/node-redis](https://github.com/redis/node-redis)
package/index.js CHANGED
@@ -34,12 +34,10 @@ class Redis extends Base {
34
34
  // 重试间隔(ms)
35
35
  "retry_delay": 1000,
36
36
  // 连接池配置
37
- "pool": {
38
- "max_clients": 100, // 最大连接数
39
- "min_idle": 5, // 最小空闲连接数
40
- "max_idle": 20, // 最大空闲连接数
41
- "idle_timeout": 30000 // 空闲超时时间(ms)
42
- }
37
+ "max_clients": 100, // 最大连接数
38
+ "min_idle": 5, // 最小空闲连接数
39
+ "max_idle": 20, // 最大空闲连接数
40
+ "idle_timeout": 30000 // 空闲超时时间(ms)
43
41
  };
44
42
  this.setConfig(config);
45
43
  // 初始化连接池
@@ -87,15 +85,15 @@ Redis.prototype._delPrefix = function (key) {
87
85
  * @return {Promise<Boolean>} 订阅结果
88
86
  */
89
87
  Redis.prototype.subscribe = async function (channel, func) {
90
- try {
91
- // 参数验证
92
- if (!channel || typeof channel !== 'string') {
93
- throw new TypeError('channel必须是非空字符串');
94
- }
95
- if (typeof func !== 'function') {
96
- throw new TypeError('func必须是函数');
97
- }
88
+ // 参数验证
89
+ if (!channel || typeof channel !== 'string') {
90
+ throw new TypeError('channel必须是非空字符串');
91
+ }
92
+ if (typeof func !== 'function') {
93
+ throw new TypeError('func必须是函数');
94
+ }
98
95
 
96
+ try {
99
97
  await this.conn.subscribe(this._addPrefix(channel));
100
98
  this.func_list[channel] = func;
101
99
  return true;
@@ -111,12 +109,12 @@ Redis.prototype.subscribe = async function (channel, func) {
111
109
  * @return {Promise<Boolean>} 取消订阅结果
112
110
  */
113
111
  Redis.prototype.unsubscribe = async function (channel) {
114
- try {
115
- // 参数验证
116
- if (!channel || typeof channel !== 'string') {
117
- throw new TypeError('channel必须是非空字符串');
118
- }
112
+ // 参数验证
113
+ if (!channel || typeof channel !== 'string') {
114
+ throw new TypeError('channel必须是非空字符串');
115
+ }
119
116
 
117
+ try {
120
118
  await this.conn.unsubscribe(this._addPrefix(channel));
121
119
  delete this.func_list[channel];
122
120
  return true;
@@ -133,15 +131,15 @@ Redis.prototype.unsubscribe = async function (channel) {
133
131
  * @return {Promise<Number>} 接收消息的客户端数量
134
132
  */
135
133
  Redis.prototype.publish = async function (channel, message) {
136
- try {
137
- // 参数验证
138
- if (!channel || typeof channel !== 'string') {
139
- throw new TypeError('channel必须是非空字符串');
140
- }
141
- if (message === undefined || message === null) {
142
- throw new TypeError('message不能为undefined或null');
143
- }
134
+ // 参数验证
135
+ if (!channel || typeof channel !== 'string') {
136
+ throw new TypeError('channel必须是非空字符串');
137
+ }
138
+ if (message === undefined || message === null) {
139
+ throw new TypeError('message不能为undefined或null');
140
+ }
144
141
 
142
+ try {
145
143
  return await this.conn.publish(this._addPrefix(channel), message);
146
144
  } catch (err) {
147
145
  this.logger('error', `发布消息到频道 ${channel} 失败:`, err);
@@ -189,49 +187,11 @@ Redis.prototype.setConfig = function (config) {
189
187
  obj = config.loadJson(__dirname);
190
188
  } else if (config) {
191
189
  // 合并配置参数
192
- if (config.pool) {
193
- // 确保连接池配置的合并不会覆盖所有默认值
194
- if (!this.config.pool) {
195
- this.config.pool = {};
196
- }
197
- Object.assign(this.config.pool, config.pool);
198
- // 删除config中的pool属性,避免后续Object.assign重复处理
199
- const configCopy = {
200
- ...config
201
- };
202
- delete configCopy.pool;
203
- Object.assign(this.config, configCopy);
204
- } else {
205
- Object.assign(this.config, config);
206
- }
190
+ Object.assign(this.config, config);
207
191
  } else {
208
192
  return;
209
193
  }
210
194
 
211
- // 确保连接池配置存在且包含所有必要字段
212
- if (!this.config.pool) {
213
- this.config.pool = {};
214
- }
215
-
216
- // 设置默认连接池配置,只覆盖未定义的字段
217
- const defaultPoolConfig = {
218
- max_clients: 100,
219
- min_idle: 5,
220
- max_idle: 20,
221
- idle_timeout: 30000
222
- };
223
-
224
- for (const key in defaultPoolConfig) {
225
- if (this.config.pool[key] === undefined) {
226
- this.config.pool[key] = defaultPoolConfig[key];
227
- }
228
- }
229
-
230
- // 如果连接池已经初始化,更新其配置
231
- if (this.connection_pool) {
232
- this.connection_pool.config = this.config.pool;
233
- }
234
-
235
195
  // 初始化连接池
236
196
  this._initPool();
237
197
  // this.logger('debug','配置已更新');
@@ -242,24 +202,16 @@ Redis.prototype.setConfig = function (config) {
242
202
  // 添加连接池初始化方法
243
203
  Redis.prototype._initPool = function () {
244
204
  // 确保连接池配置存在
245
- if (!this.config.pool) {
246
- this.config.pool = {
247
- max_clients: 100,
248
- min_idle: 5,
249
- max_idle: 20,
250
- idle_timeout: 30000
251
- };
252
- }
253
205
 
254
206
  // 初始化连接池相关属性
255
207
  this.connection_pool = {
256
208
  available: [],
257
209
  in_use: new Set(),
258
- config: this.config.pool // 直接引用配置对象,确保同步更新
210
+ config: this.config // 直接引用配置对象,确保同步更新
259
211
  };
260
212
 
261
213
  // 记录连接池初始化
262
- // this.logger('debug','连接池已初始化,配置:', this.config.pool);
214
+ // this.logger('debug','连接池已初始化,配置:', this.config);
263
215
  };
264
216
 
265
217
  /**
@@ -552,12 +504,6 @@ Redis.prototype.isConnected = function () {
552
504
  return this.connected && this.conn && this.conn.isReady;
553
505
  };
554
506
 
555
- /**
556
- * @description 查询或是设置缓存过期时间
557
- * @param {String} key 键
558
- * @param {Number} seconds 秒, 为空则查询有效时长
559
- * @return {Promise<Number|Boolean>} 查询时长或设置结果, 时长为-1表示永不过期
560
- */
561
507
  /**
562
508
  * 获取或设置键的过期时间
563
509
  * @param {String} key 键名
@@ -565,11 +511,12 @@ Redis.prototype.isConnected = function () {
565
511
  * @return {Promise<Number|Boolean>} 不传seconds时返回剩余过期时间(-1表示无过期设置,-2表示已过期),传seconds时返回是否设置成功
566
512
  */
567
513
  Redis.prototype.ttl = async function (key, seconds) {
514
+ // 参数验证
515
+ if (!key || typeof key !== 'string') {
516
+ throw new TypeError('key必须是非空字符串');
517
+ }
518
+
568
519
  try {
569
- // 参数验证
570
- if (!key || typeof key !== 'string') {
571
- throw new TypeError('key必须是非空字符串');
572
- }
573
520
 
574
521
  const connection = await this._getConnection();
575
522
  try {
@@ -620,16 +567,15 @@ Redis.prototype.ttl = async function (key, seconds) {
620
567
  * @return {Promise<Number>} 计算后的结果
621
568
  */
622
569
  Redis.prototype.addInt = async function (key, num, seconds = 0) {
570
+ // 参数验证
571
+ if (!key || typeof key !== 'string') {
572
+ throw new TypeError('key必须是非空字符串');
573
+ }
574
+ if (typeof num !== 'number' || isNaN(num) || !Number.isInteger(num)) {
575
+ throw new TypeError('num必须是有效整数');
576
+ }
577
+
623
578
  try {
624
- // 参数验证
625
- if (!key || typeof key !== 'string') {
626
- this.logger('error', '参数错误: 键必须是非空字符串');
627
- return false;
628
- }
629
- if (typeof num !== 'number' || isNaN(num) || !Number.isInteger(num)) {
630
- this.logger('error', '参数错误: 数值必须是有效整数');
631
- return false;
632
- }
633
579
 
634
580
  // 触发前置事件,允许修改或阻止操作
635
581
  const ctx = {
@@ -738,17 +684,18 @@ Redis.prototype.addInt = async function (key, num, seconds = 0) {
738
684
  * @return {Promise<Number>} 计算后的结果
739
685
  */
740
686
  Redis.prototype.addFloat = async function (key, num, seconds = 0) {
741
- try {
742
- // 参数验证
743
- if (!key || typeof key !== 'string') {
744
- throw new TypeError('key必须是非空字符串');
745
- }
687
+ // 参数验证
688
+ if (!key || typeof key !== 'string') {
689
+ throw new TypeError('key必须是非空字符串');
690
+ }
746
691
 
747
- // 验证num参数
748
- num = parseFloat(num);
749
- if (isNaN(num)) {
750
- throw new TypeError('num必须是有效的数值');
751
- }
692
+ // 验证num参数
693
+ num = parseFloat(num);
694
+ if (isNaN(num)) {
695
+ throw new TypeError('num必须是有效的数值');
696
+ }
697
+
698
+ try {
752
699
 
753
700
  // 触发前置事件,允许修改或阻止操作
754
701
  const ctx = {
@@ -2289,7 +2236,7 @@ Redis.prototype._recycleConnection = function (connection) {
2289
2236
  * @description 删除哈希字段
2290
2237
  * @param {String} key 键
2291
2238
  * @param {String|Array<String>} fields 字段名或字段名数组
2292
- * @return {Promise<Boolean>} 操作结果
2239
+ * @return {Promise<Number>} 删除的字段数量
2293
2240
  */
2294
2241
  Redis.prototype.hdel = async function (key, fields) {
2295
2242
  try {
@@ -2321,23 +2268,24 @@ Redis.prototype.hdel = async function (key, fields) {
2321
2268
  finalFields = [finalFields];
2322
2269
  }
2323
2270
 
2271
+ let deletedCount = 0;
2324
2272
  // 执行删除操作
2325
2273
  if (typeof connection.hDel === 'function') {
2326
- await connection.hDel(finalKey, finalFields);
2274
+ deletedCount = await connection.hDel(finalKey, finalFields);
2327
2275
  } else if (typeof connection.execute === 'function') {
2328
- await connection.execute('HDEL', [finalKey, ...finalFields]);
2276
+ deletedCount = await connection.execute('HDEL', [finalKey, ...finalFields]);
2329
2277
  } else {
2330
2278
  this.logger('error', '连接对象不支持hDel操作');
2331
- success = false;
2279
+ deletedCount = 0;
2332
2280
  }
2333
2281
 
2334
2282
  // 触发后置事件
2335
2283
  this.emit('hdel:after', {
2336
2284
  key: finalKey,
2337
2285
  value: finalFields,
2338
- success
2286
+ deletedCount
2339
2287
  });
2340
- return success;
2288
+ return deletedCount;
2341
2289
  } finally {
2342
2290
  this._recycleConnection(connection);
2343
2291
  }
@@ -2349,7 +2297,7 @@ Redis.prototype.hdel = async function (key, fields) {
2349
2297
  error: err
2350
2298
  });
2351
2299
  this.logger('error', `删除哈希字段失败 [${key}]:`, err);
2352
- return false;
2300
+ return 0; // 与Redis语义保持一致,返回删除的字段数量
2353
2301
  }
2354
2302
  };
2355
2303
 
@@ -2543,7 +2491,7 @@ Redis.prototype._getConnection = function () {
2543
2491
  // 如果连接数未达到上限,创建新连接
2544
2492
  const totalConnections = this.connection_pool.available.length + this.connection_pool.in_use
2545
2493
  .size;
2546
- if (totalConnections < this.connection_pool.config.max_clients) {
2494
+ if (totalConnections < this.config.max_clients) {
2547
2495
  this._createConnection().then(connection => {
2548
2496
  this.connection_pool.in_use.add(connection);
2549
2497
  resolve(connection);
@@ -2571,7 +2519,7 @@ Redis.prototype._releaseConnection = function (connection) {
2571
2519
  this.connection_pool.in_use.delete(connection);
2572
2520
 
2573
2521
  // 检查是否超过最大空闲连接数
2574
- if (this.connection_pool.available.length < this.connection_pool.config.max_idle) {
2522
+ if (this.connection_pool.available.length < this.config.max_idle) {
2575
2523
  this.connection_pool.available.push(connection);
2576
2524
  } else {
2577
2525
  // 否则关闭多余的连接
@@ -2646,7 +2594,7 @@ Redis.prototype.hset = async function (key, field, value) {
2646
2594
  value: finalValue,
2647
2595
  success: true
2648
2596
  });
2649
- return result > 0; // 如果field是新的,hSet返回1,否则返回0
2597
+ return true; // hSet操作成功返回true
2650
2598
  } finally {
2651
2599
  this._recycleConnection(connection);
2652
2600
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mm_redis",
3
- "version": "2.0.8",
3
+ "version": "2.0.9",
4
4
  "description": "高效的Redis客户端封装库,提供连接池管理、数据类型操作、错误处理和批量操作优化",
5
5
  "main": "index.js",
6
6
  "scripts": {