mm_sqlite 1.1.4 → 1.1.6

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 (6) hide show
  1. package/README.md +168 -102
  2. package/db.js +94 -115
  3. package/index.js +756 -555
  4. package/package.json +2 -2
  5. package/sql.js +245 -372
  6. package/sql_builder.js +0 -375
package/README.md CHANGED
@@ -7,31 +7,21 @@
7
7
  [![node version](https://img.shields.io/node/v/mm_sqlite.svg?style=flat-square)](https://nodejs.org/en/)
8
8
  [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](LICENSE)
9
9
 
10
- ## 特性
11
-
12
- - 🚀 **高性能优化**:经过深度优化的SQL构建器和连接管理
13
- - 🔄 **完全兼容**:与mm_mysql模块API完全兼容
14
- - 📊 **内存优化**:优化的内存使用,减少GC压力
15
- - 🔧 **链式调用**:流畅的SQL构建器链式调用
16
- - 🛡️ **错误处理**:完善的错误处理机制
17
- - 📈 **性能监控**:内置性能测试和内存监控
18
-
19
10
  ## 安装
20
11
 
21
- ### 使用 npm
22
12
  ```bash
23
13
  npm install mm_sqlite --save
24
14
  ```
25
15
 
26
- ### 使用 yarn
27
- ```bash
28
- yarn add mm_sqlite
29
- ```
16
+ ## 特性
30
17
 
31
- ### 使用 pnpm
32
- ```bash
33
- pnpm add mm_sqlite
34
- ```
18
+ - 🚀 **高性能优化**:经过深度优化的SQL构建器和连接管理
19
+ - 🔄 **完全兼容**:与mm_mysql模块API完全兼容
20
+ - 📊 **内存优化**:优化的内存使用,减少GC压力
21
+ - 🔧 **链式调用**:流畅的SQL构建器链式调用
22
+ - 🛡️ **错误处理**:完善的错误处理机制
23
+ - 📈 **连接池支持**:支持连接池模式,提高并发性能
24
+ - 🔒 **事务支持**:完整的事务处理机制
35
25
 
36
26
  ## 依赖要求
37
27
 
@@ -51,10 +41,23 @@ const { Sqlite } = require('mm_sqlite');
51
41
  const sqlite = new Sqlite({
52
42
  dir: './db/', // 数据库文件存储目录
53
43
  database: 'test', // 数据库文件名(不包含扩展名)
54
- timeout: 30000, // 查询超时时间(毫秒)
55
- retry_count: 3, // 失败重试次数
56
- conn_timeout: 30000, // 连接超时时间(毫秒)
57
- enablePerformanceLog: false // 是否启用性能日志
44
+ charset: 'utf8mb4', // 字符集
45
+ timezone: '+08:00', // 时区
46
+ connect_timeout: 20000, // 连接超时时间(毫秒)
47
+ acquire_timeout: 20000, // 获取连接超时时间(毫秒)
48
+ query_timeout: 20000, // 查询超时时间(毫秒)
49
+ connection_limit: 1, // 连接限制(>1启用连接池)
50
+ enable_keep_alive: true, // 启用保活
51
+ keep_alive_initial_delay: 10000, // 保活初始延迟
52
+ enable_reconnect: true, // 启用重连
53
+ reconnect_interval: 1000, // 重连间隔
54
+ max_reconnect_attempts: 5, // 最大重连尝试次数
55
+ wait_for_connections: true, // 等待连接
56
+ pool_min: 1, // 连接池最小连接数
57
+ pool_max: 5, // 连接池最大连接数
58
+ pool_acquire_timeout: 30000, // 连接池获取超时
59
+ pool_idle_timeout: 60000, // 连接池空闲超时
60
+ pool_reap_interval: 1000 // 连接池清理间隔
58
61
  });
59
62
 
60
63
  // 打开数据库连接
@@ -170,34 +173,38 @@ await sqlite.close();
170
173
 
171
174
  ```javascript
172
175
  // 开始事务
173
- await sqlite.beginTransaction();
176
+ const transaction = await sqlite.beginTransaction();
174
177
 
175
178
  try {
176
- // 插入数据
177
- await sqlite.table('users').add({
178
- name: '张三',
179
- email: 'zhangsan@example.com',
180
- status: 'active'
181
- });
182
-
183
- // 插入关联数据
184
- await sqlite.table('profiles').add({
185
- user_id: 1,
186
- bio: '这是一个测试用户'
187
- });
179
+ // 在事务中执行操作
180
+ await transaction.exec('INSERT INTO users (username, email) VALUES (?, ?)', ['张三', 'zhangsan@example.com']);
181
+ await transaction.exec('INSERT INTO profiles (user_id, bio) VALUES (?, ?)', [1, '这是一个测试用户']);
188
182
 
189
183
  // 提交事务
190
- await sqlite.commit();
184
+ await transaction.commit();
191
185
  } catch (error) {
192
186
  // 回滚事务
193
- await sqlite.rollback();
187
+ await transaction.rollback();
194
188
  console.error('事务执行失败:', error);
195
189
  }
196
190
  ```
197
191
 
198
- #### 复杂查询
192
+ #### 使用事务包装器
199
193
 
200
194
  ```javascript
195
+ // 使用事务包装器简化事务处理
196
+ const result = await sqlite.transaction(async (transaction) => {
197
+ // 在事务中执行操作
198
+ await transaction.exec('INSERT INTO users (username, email) VALUES (?, ?)', ['李四', 'lisi@example.com']);
199
+ await transaction.exec('INSERT INTO profiles (user_id, bio) VALUES (?, ?)', [2, '这是另一个测试用户']);
200
+
201
+ return { success: true };
202
+ });
203
+
204
+ console.log('事务执行结果:', result);
205
+ ```
206
+
207
+ #### 复杂查询
201
208
  // 多表连接查询
202
209
  const results = await sqlite
203
210
  .table('users')
@@ -254,111 +261,170 @@ new Sqlite(config)
254
261
  **配置参数:**
255
262
  - `config.dir` - 数据库文件存储目录,默认为`'./db/'`
256
263
  - `config.database` - 数据库文件名,默认为`'mm'`
257
- - `config.timeout` - 查询超时时间,默认`30000ms`
258
- - `config.retry_count` - 失败重试次数,默认`3`
259
- - `config.conn_timeout` - 连接超时时间,默认`30000ms`
260
- - `config.enablePerformanceLog` - 是否启用性能日志,默认`false`
261
- - `config.debug` - 是否启用调试模式,默认`false`
264
+ - `config.charset` - 字符集,默认为`'utf8mb4'`
265
+ - `config.timezone` - 时区,默认为`'+08:00'`
266
+ - `config.connect_timeout` - 连接超时时间,默认`20000ms`
267
+ - `config.acquire_timeout` - 获取连接超时时间,默认`20000ms`
268
+ - `config.query_timeout` - 查询超时时间,默认`20000ms`
269
+ - `config.connection_limit` - 连接限制(>1启用连接池),默认`1`
270
+ - `config.enable_keep_alive` - 启用保活,默认`true`
271
+ - `config.keep_alive_initial_delay` - 保活初始延迟,默认`10000ms`
272
+ - `config.enable_reconnect` - 启用重连,默认`true`
273
+ - `config.reconnect_interval` - 重连间隔,默认`1000ms`
274
+ - `config.max_reconnect_attempts` - 最大重连尝试次数,默认`5`
275
+ - `config.wait_for_connections` - 等待连接,默认`true`
276
+ - `config.pool_min` - 连接池最小连接数,默认`1`
277
+ - `config.pool_max` - 连接池最大连接数,默认`5`
278
+ - `config.pool_acquire_timeout` - 连接池获取超时,默认`30000ms`
279
+ - `config.pool_idle_timeout` - 连接池空闲超时,默认`60000ms`
280
+ - `config.pool_reap_interval` - 连接池清理间隔,默认`1000ms`
262
281
 
263
282
  #### 主要方法
264
283
 
265
284
  - `open(timeout)` - 打开数据库连接,返回`Promise<Boolean>`
266
285
  - `close()` - 关闭数据库连接,返回`Promise<Boolean>`
267
286
  - `getConn(timeout)` - 获取数据库连接,返回`Promise<Connection>`
268
- - `run(sql, params, timeout)` - 执行SQL语句(非查询操作),返回`Promise<Object>`
269
- - `exec(sql, params, timeout)` - 执行SQL查询,返回`Promise<Array>`
270
- - `beginTransaction()` - 开始事务,返回`Promise<void>`
271
- - `commit()` - 提交事务,返回`Promise<void>`
272
- - `rollback()` - 回滚事务,返回`Promise<void>`
273
- - `transaction(fn)` - 执行事务,返回`Promise<any>`
274
- - `table(tableName)` - 设置表名,返回`Sql`实例
287
+ - `run(sql, params, timeout)` - 执行SQL查询语句,返回`Promise<Array>`
288
+ - `exec(sql, params, timeout)` - 执行SQL语句(非查询操作),返回`Promise<Object>`
289
+ - `read(table, condition, options)` - 读取整张表的数据,返回`Promise<Array>`
290
+ - `db(database)` - 获取数据库操作实例,返回`DB`实例
291
+ - `beginTransaction()` - 开始事务,返回`Promise<Object>`(事务对象)
292
+ - `transaction(callback)` - 在事务中执行多个操作,返回`Promise<*>`
275
293
 
276
- ### Sql类
294
+ #### 事务对象方法
277
295
 
278
- #### 数据操作方法
296
+ - `commit()` - 提交事务
297
+ - `rollback()` - 回滚事务
298
+ - `exec(sql, params)` - 在事务中执行SQL语句
279
299
 
280
- - `add(body)` - 添加单条数据,返回Promise<Object>
281
- - `del(query, like)` - 删除数据,返回Promise<Object>
282
- - `set(query, body, like)` - 更新数据,返回Promise<Object>
283
- - `get(query, sort, view, like, timeout)` - 查询多条数据,返回Promise<Array>
284
- - `getObj(query, sort, view, like, timeout)` - 获取单条记录,返回Promise<Object|null>
300
+ ### DB类
285
301
 
286
- #### 批量操作方法
302
+ DB类继承自Sql类,提供SQL构建器功能。
287
303
 
288
- - `addList(list, lock, batchSize, timeout)` - 批量添加数据,返回Promise<Object>
289
- - `delList(list, like, batchSize, timeout)` - 批量删除数据,返回Promise<Object>
290
- - `setList(list, like, batchSize, timeout)` - 批量更新数据,返回Promise<Object>
291
-
292
- #### 统计方法
304
+ #### 主要方法
293
305
 
294
- - `count(query, like, timeout)` - 统计记录数,返回Promise<Number>
295
- - `getCount(query, like, timeout)` - 查询数据并返回总数,返回Promise<{count: Number, data: Array}>
296
- - `groupCount(query, groupby, view, sort)` - 分组统计,返回Promise<Array>
297
- - `groupSum(query, groupby, view, sort)` - 分组求和,返回Promise<Array>
298
- - `groupAvg(query, groupby, view, sort)` - 分组平均值,返回Promise<Array>
306
+ - `table(tableName)` - 设置表名,返回当前实例
307
+ - `add(body)` - 添加单条数据,返回`Promise<Object>`
308
+ - `del(query, like)` - 删除数据,返回`Promise<Object>`
309
+ - `set(query, body, like)` - 更新数据,返回`Promise<Object>`
310
+ - `get(query, sort, view, like, timeout)` - 查询多条数据,返回`Promise<Array>`
311
+ - `getObj(query, sort, view, like, timeout)` - 获取单条记录,返回`Promise<Object|null>`
312
+ - `addList(list, lock, batchSize, timeout)` - 批量添加数据,返回`Promise<Object>`
313
+ - `delList(list, like, batchSize, timeout)` - 批量删除数据,返回`Promise<Object>`
314
+ - `count(query, like, timeout)` - 统计记录数,返回`Promise<Number>`
315
+ - `groupCount(query, groupby, view, sort)` - 分组统计,返回`Promise<Array>`
316
+ - `groupSum(query, groupby, view, sort)` - 分组求和,返回`Promise<Array>`
317
+ - `groupAvg(query, groupby, view, sort)` - 分组平均值,返回`Promise<Array>`
318
+
319
+ #### SQL构建器方法
320
+
321
+ - `select(fields)` - 设置查询字段
322
+ - `where(condition)` - 设置查询条件
323
+ - `orWhere(condition)` - 设置OR查询条件
324
+ - `like(field, value)` - 设置LIKE查询条件
325
+ - `orderBy(field, direction)` - 设置排序
326
+ - `groupBy(field)` - 设置分组
327
+ - `having(condition)` - 设置HAVING条件
328
+ - `limit(count)` - 设置限制数量
329
+ - `offset(count)` - 设置偏移量
330
+ - `join(table, condition)` - 设置表连接
299
331
 
300
332
  ## 错误处理
301
333
 
302
334
  模块提供完善的错误处理机制:
303
335
 
336
+ 1. **参数验证**:所有公开方法都会验证输入参数,参数不符合要求时会抛出`TypeError`
337
+ 2. **SQL错误捕获**:SQL执行错误会被捕获并记录到日志中
338
+ 3. **连接错误处理**:连接失败时会自动重连,超过最大重试次数后抛出错误
339
+ 4. **事务错误处理**:事务执行失败时会自动回滚,确保数据一致性
340
+
341
+ 错误处理示例:
342
+
304
343
  ```javascript
344
+ // 参数验证错误
305
345
  try {
306
- const result = await sqlite.table('users').where({ id: 999 }).first();
307
- if (!result) {
308
- throw new Error('用户不存在');
309
- }
310
- } catch (error) {
311
- console.error('查询失败:', error.message);
312
- // 错误码和详细信息
313
- console.error('错误码:', error.code);
314
- console.error('SQL语句:', error.sql);
346
+ await db.add(null); // 抛出TypeError
347
+ } catch (err) {
348
+ console.error('参数错误:', err.message);
349
+ }
350
+
351
+ // SQL执行错误
352
+ try {
353
+ await db.exec('SELECT * FROM non_existent_table');
354
+ } catch (err) {
355
+ console.error('SQL错误:', err.message);
356
+ }
357
+
358
+ // 事务错误处理
359
+ try {
360
+ await sqlite.transaction(async (tx) => {
361
+ await tx.exec('INSERT INTO users (name) VALUES (?)', ['Alice']);
362
+ await tx.exec('INSERT INTO users (name) VALUES (?)', [null]); // 触发错误
363
+ });
364
+ } catch (err) {
365
+ console.error('事务执行失败:', err.message);
315
366
  }
316
367
  ```
317
368
 
318
369
  ## 性能监控
319
370
 
320
- 模块设计注重性能优化,您可以通过以下方式监控性能:
371
+ 模块内置连接池和性能优化功能:
372
+
373
+ 1. **连接池管理**:自动管理数据库连接,提高并发性能
374
+ 2. **连接复用**:连接使用完毕后自动归还到连接池
375
+ 3. **连接保活**:定期检查连接状态,自动重连失效连接
376
+ 4. **超时控制**:支持连接超时、查询超时等配置
377
+
378
+ 连接池配置示例:
321
379
 
322
380
  ```javascript
323
- // 启用性能日志
324
381
  const sqlite = new Sqlite({
325
- database: './data/test.db',
326
- enablePerformanceLog: true
382
+ connection_limit: 5, // 启用连接池,最大5个连接
383
+ pool_min: 1, // 最小连接数
384
+ pool_max: 5, // 最大连接数
385
+ pool_idle_timeout: 60000, // 空闲超时60秒
386
+ enable_keep_alive: true, // 启用保活
387
+ enable_reconnect: true // 启用自动重连
327
388
  });
328
-
329
- // 测试特定操作的性能
330
- console.time('query_test');
331
- const results = await sqlite.table('users').get();
332
- console.timeEnd('query_test');
333
389
  ```
334
390
 
335
391
  对于大规模应用,建议在生产环境前进行压力测试,确保数据库操作满足性能要求。
336
392
 
337
393
  ## 兼容性
338
394
 
339
- - Node.js 14.0+ (推荐使用最新的LTS版本)
340
- - SQLite3 3.0+
341
- - 与mm_mysql模块API完全兼容
395
+ - **Node.js版本**:支持 Node.js 12.0 及以上版本
396
+ - **SQLite版本**:支持 SQLite 3.0 及以上版本
397
+ - **操作系统**:支持 Windows、Linux、macOS
398
+
399
+ ## FAQ
400
+
401
+ ### Q: 如何处理数据库文件不存在的情况?
402
+ A: 模块会自动创建数据库文件,无需手动创建。
342
403
 
343
- ## 常见问题解答 (FAQ)
404
+ ### Q: 如何优化查询性能?
405
+ A: 建议使用索引、合理设计表结构、避免全表扫描。
344
406
 
345
- **Q: 如何处理大量数据的插入操作?**
346
- A: 对于大量数据插入,建议使用`addList`方法配合事务处理,这样可以显著提高性能。
407
+ ### Q: 如何处理并发访问?
408
+ A: 模块内置连接池机制,支持并发访问。当连接数超过1时自动启用连接池。
347
409
 
348
- **Q: 为什么连接池大小设置为1?**
349
- A: SQLite是单文件数据库,在大多数情况下单连接已经足够高效。多连接可能会导致锁竞争,反而降低性能。
410
+ ### Q: 如何备份数据库?
411
+ A: 可以直接复制数据库文件进行备份。
350
412
 
351
- **Q: 如何处理数据库文件路径?**
352
- A: 可以使用相对路径或绝对路径。建议使用绝对路径以避免路径解析问题。
413
+ ### Q: 如何查看SQL执行日志?
414
+ A: 启用调试模式即可查看详细的SQL执行日志。
353
415
 
354
- **Q: 事务处理是否支持嵌套?**
355
- A: 目前不支持嵌套事务,但可以在一个事务中执行多个操作。
416
+ ### Q: 连接池如何工作?
417
+ A: 当`connection_limit`大于1时启用连接池,连接池会自动管理连接的获取和释放。
356
418
 
357
- **Q: 如何启用调试模式?**
358
- A: 在创建Sqlite实例时,设置`debug: true`配置项即可启用调试模式。
419
+ ### Q: 事务处理是否安全?
420
+ A: 是的,事务处理包含完整的错误处理机制,失败时会自动回滚。
421
+
422
+ ### Q: 支持哪些SQL操作?
423
+ A: 支持标准的CRUD操作、复杂查询、事务处理、批量操作等。
424
+
425
+ ## 贡献
359
426
 
360
- **Q: 如何处理SQLite的锁问题?**
361
- A: 避免长时间运行的事务,使用适当的事务隔离级别,并确保在操作完成后及时提交或回滚事务。
427
+ 欢迎提交 Issue 和 Pull Request 来改进这个模块。
362
428
 
363
429
  ## 许可证
364
430