mm_sqlite 1.3.9 → 1.4.0

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/index.js CHANGED
@@ -3,6 +3,8 @@ const {
3
3
  DB
4
4
  } = require('./db');
5
5
  const { Base } = require('mm_expand');
6
+ const SQLitePool = require('./pool');
7
+
6
8
 
7
9
  /**
8
10
  * SQLite数据库操作类
@@ -21,23 +23,15 @@ class SQLite extends Base {
21
23
  database: 'mm',
22
24
  charset: 'utf8mb4',
23
25
  timezone: '+08:00',
24
- connect_timeout: 5000, // 减少连接超时时间
25
- acquire_timeout: 5000, // 减少获取连接超时时间
26
- query_timeout: 10000, // 减少查询超时时间
27
- connection_limit: 10, // 减少最大连接数
28
- queue_limit: 0,
29
- enable_keep_alive: false, // SQLite不需要保持连接
30
- keep_alive_initial_delay: 0,
31
- enable_reconnect: false, // SQLite不需要重连
32
- reconnect_interval: 0,
33
- max_reconnect_attempts: 0,
34
- wait_for_connections: false,
35
- // 连接池相关配置
36
- pool_min: 1,
37
- pool_max: 3, // 减少最大连接池大小
38
- pool_acquire_timeout: 5000, // 减少连接池获取超时
39
- pool_idle_timeout: 30000, // 减少空闲超时
40
- pool_reap_interval: 5000 // 减少回收间隔
26
+ connect_timeout: 5000, // 连接超时时间
27
+ acquire_timeout: 5000, // 获取连接超时时间
28
+ query_timeout: 10000, // 查询超时时间
29
+ // 连接池配置(统一使用连接池模式)
30
+ pool_min: 1, // 最小连接数
31
+ pool_max: 3, // 最大连接数
32
+ pool_acquire_timeout: 5000, // 连接池获取超时
33
+ pool_idle_timeout: 30000, // 空闲超时
34
+ pool_reap_interval: 5000 // 回收间隔
41
35
  };
42
36
 
43
37
  /**
@@ -46,9 +40,6 @@ class SQLite extends Base {
46
40
  */
47
41
  constructor(config) {
48
42
  super(config);
49
- this._pool_connections = [];
50
- this._pool_available = [];
51
- this._pool_waiting = [];
52
43
  }
53
44
  }
54
45
 
@@ -58,7 +49,6 @@ class SQLite extends Base {
58
49
  */
59
50
  SQLite.prototype._preset = function () {
60
51
  this._connection = null;
61
- this._pool = null;
62
52
  this._status = 'closed';
63
53
  this._last_connect_time = 0;
64
54
  this._reconnecting = false;
@@ -67,29 +57,8 @@ SQLite.prototype._preset = function () {
67
57
  this._db = null;
68
58
  this._open = false;
69
59
  this._conn_retry_count = 0;
70
-
71
- // 连接池相关属性
72
- this._use_pool = this.config.connection_limit > 1;
73
- this._pool_reaper = null;
74
- };
75
-
76
- /**
77
- * 初始化服务
78
- * @returns {Promise<void>}
79
- */
80
- SQLite.prototype._initService = async function () {
81
- if (this._is_inited) {
82
- this.log('warn', 'SQLite服务已初始化');
83
- return;
84
- }
85
-
86
- try {
87
- this.log('debug', '初始化SQLite服务', { config: this.config });
88
- this._is_inited = true;
89
- this.log('debug', 'SQLite服务初始化完成');
90
- } catch (error) {
91
- this.log('error', 'SQLite服务初始化失败', error);
92
- }
60
+ // 初始化连接池实例
61
+ this._pool = new SQLitePool(this.config, this._getDbFilename.bind(this), this.log.bind(this));
93
62
  };
94
63
 
95
64
  /**
@@ -106,24 +75,7 @@ SQLite.prototype._getDbFilename = function () {
106
75
  };
107
76
 
108
77
  /**
109
- * 内部打开数据库连接
110
- * @private
111
- * @returns {Promise<void>}
112
- */
113
- SQLite.prototype._openInternal = async function () {
114
- return new Promise((resolve, reject) => {
115
- this._db = new sqlite3.Database(this._getDbFilename(), (err) => {
116
- if (err) {
117
- reject(err);
118
- } else {
119
- resolve();
120
- }
121
- });
122
- });
123
- };
124
-
125
- /**
126
- * 打开数据库连接
78
+ * 打开数据库连接(统一使用连接池模式)
127
79
  * @param {number} timeout - 超时时间(毫秒)
128
80
  * @returns {Promise<boolean>}
129
81
  * @throws {TypeError} 当timeout参数无效时
@@ -139,65 +91,16 @@ SQLite.prototype.open = async function (timeout) {
139
91
  return true;
140
92
  }
141
93
 
142
- const connect_timeout = timeout || this.config.connect_timeout || 10000;
143
94
  this._status = 'connecting';
144
95
 
145
96
  try {
146
97
  this.config.dir.addDir();
147
- if (this._use_pool) {
148
- // 使用连接池模式
149
- await this._initPool();
150
- this._last_connect_time = Date.now();
151
- this._status = 'connected';
152
- this.log('info', '数据库连接池初始化成功', {
153
- dir: this.config.dir,
154
- database: this.config.database,
155
- pool_min: this.config.pool_min,
156
- pool_max: this.config.pool_max
157
- });
158
- return true;
159
- } else {
160
- // 使用单连接模式 - 替换Promise.race为更可靠的超时控制
161
- let timeout_id = null;
162
- let connection_success = false;
163
-
164
- try {
165
- // 设置超时控制
166
- const timeout_promise = new Promise((resolve, reject) => {
167
- timeout_id = setTimeout(() => {
168
- if (!connection_success) {
169
- reject(new Error(`数据库连接超时(${connect_timeout}ms)`));
170
- }
171
- }, connect_timeout);
172
- });
173
-
174
- // 执行连接
175
- await this._openInternal();
176
- connection_success = true;
177
-
178
- // 清除超时定时器
179
- if (timeout_id) {
180
- clearTimeout(timeout_id);
181
- timeout_id = null;
182
- }
183
98
 
184
- this._last_connect_time = Date.now();
185
- this._status = 'connected';
186
- this.log('info', '数据库连接成功', {
187
- dir: this.config.dir,
188
- database: this.config.database
189
- });
190
- return true;
191
- } catch (connection_err) {
192
- // 确保超时定时器被清除
193
- if (timeout_id) {
194
- clearTimeout(timeout_id);
195
- timeout_id = null;
196
- }
197
- this.log('error', '连接过程错误详情', connection_err);
198
- throw connection_err;
199
- }
200
- }
99
+ // 统一使用连接池模式
100
+ await this._pool.init();
101
+ this._last_connect_time = Date.now();
102
+ this._status = 'connected';
103
+ return true;
201
104
  } catch (err) {
202
105
  this._status = 'closed';
203
106
  this.log('error', '数据库连接失败', err);
@@ -206,7 +109,7 @@ SQLite.prototype.open = async function (timeout) {
206
109
  };
207
110
 
208
111
  /**
209
- * 关闭数据库连接
112
+ * 关闭数据库连接(统一使用连接池模式)
210
113
  * @returns {Promise<boolean>}
211
114
  */
212
115
  SQLite.prototype.close = function () {
@@ -217,32 +120,12 @@ SQLite.prototype.close = function () {
217
120
 
218
121
  return new Promise((resolve) => {
219
122
  try {
220
- if (this._use_pool) {
221
- // 关闭连接池
222
- this._closePool();
223
- this._db = null;
224
- this._open = false;
225
- this._status = 'closed';
226
- this.log('info', '数据库连接池已关闭');
227
- resolve(true);
228
- } else if (this._db) {
229
- // 单连接模式
230
- this.log('debug', '关闭数据库连接');
231
- this._db.close((err) => {
232
- if (err) {
233
- this.log('error', '关闭数据库失败', err);
234
- } else {
235
- this.log('info', '数据库已关闭');
236
- }
237
- this._db = null;
238
- this._open = false;
239
- this._status = 'closed';
240
- resolve(!err);
241
- });
242
- } else {
243
- this._status = 'closed';
244
- resolve(true);
245
- }
123
+ // 统一关闭连接池
124
+ this._pool.close();
125
+ this._db = null;
126
+ this._open = false;
127
+ this._status = 'closed';
128
+ resolve(true);
246
129
  } catch (err) {
247
130
  this.log('error', '关闭数据库连接时发生异常', err);
248
131
  this._status = 'closed';
@@ -252,7 +135,7 @@ SQLite.prototype.close = function () {
252
135
  };
253
136
 
254
137
  /**
255
- * 获取数据库连接
138
+ * 获取数据库连接(统一使用连接池模式)
256
139
  * @param {number} timeout - 超时时间(毫秒)
257
140
  * @returns {Promise<object>}
258
141
  * @throws {TypeError} 当timeout参数无效时
@@ -270,32 +153,8 @@ SQLite.prototype.getConn = async function (timeout) {
270
153
  }
271
154
 
272
155
  try {
273
- if (this._use_pool) {
274
- // 从连接池获取连接
275
- return await this._getPoolConnection();
276
- } else {
277
- // 单连接模式 - 替换Promise.race为更可靠的超时控制
278
- let timeout_id = null;
279
-
280
- try {
281
- return await new Promise((resolve, reject) => {
282
- // 设置超时定时器
283
- timeout_id = setTimeout(() => {
284
- reject(new Error(`获取数据库连接超时(${acquire_timeout}ms)`));
285
- }, acquire_timeout);
286
-
287
- // 直接返回连接,因为这是单连接模式
288
- resolve(this._db);
289
- });
290
- } catch (error) {
291
- // 确保超时定时器被清除
292
- if (timeout_id) {
293
- clearTimeout(timeout_id);
294
- timeout_id = null;
295
- }
296
- throw error;
297
- }
298
- }
156
+ // 统一从连接池获取连接
157
+ return await this._pool.getConnection(acquire_timeout);
299
158
  } catch (error) {
300
159
  this.log('error', '获取连接失败', error);
301
160
  return null;
@@ -323,18 +182,16 @@ SQLite.prototype.run = async function (sql, params = [], timeout = 30000) {
323
182
  }
324
183
 
325
184
  this.error = null;
185
+ this.sql = '';
326
186
  let conn = null;
327
187
  const query_timeout = timeout || this.config.query_timeout || 30000;
328
-
188
+ let ret = [];
329
189
  try {
330
190
  // 获取连接
331
191
  conn = await this.getConn(query_timeout);
332
-
333
- const self = this;
334
- // 替换Promise.race为更可靠的超时控制
335
192
  let timeout_id = null;
336
-
337
- const result = await new Promise((resolve, reject) => {
193
+
194
+ ret = await new Promise((resolve, reject) => {
338
195
  // 设置超时定时器
339
196
  timeout_id = setTimeout(() => {
340
197
  reject(new Error(`SQL查询超时: ${timeout}ms`));
@@ -347,14 +204,8 @@ SQLite.prototype.run = async function (sql, params = [], timeout = 30000) {
347
204
  clearTimeout(timeout_id);
348
205
  timeout_id = null;
349
206
  }
350
-
351
207
  if (error) {
352
- self.sql = sql;
353
- self.error = {
354
- code: error.errno,
355
- message: error.message
356
- };
357
- // 不抛出错误,保持与MySQL一致的错误处理行为
208
+ reject(error);
358
209
  resolve([]);
359
210
  } else {
360
211
  // 保持与MySQL兼容的返回值格式,始终返回数组
@@ -362,25 +213,19 @@ SQLite.prototype.run = async function (sql, params = [], timeout = 30000) {
362
213
  }
363
214
  });
364
215
  });
365
-
366
- // 连接池模式下释放连接
367
- if (this._use_pool && conn) {
368
- this._releasePoolConnection(conn);
369
- }
370
-
371
- return result;
372
- } catch (err) {
373
- this.log('error', 'SQL执行失败', err);
374
-
375
- // 连接池模式下释放连接
376
- if (this._use_pool && conn) {
377
- this._releasePoolConnection(conn);
378
- }
379
-
380
- // 简化错误处理:SQLite不需要复杂的连接错误处理
381
- // 直接返回空数组,保持与MySQL一致的错误处理行为
382
- return [];
216
+ } catch (error) {
217
+ this.log('error', 'SQL执行失败', error);
218
+ this.sql = sql;
219
+ this.error = {
220
+ code: error.errno,
221
+ message: error.message
222
+ };
223
+ ret = [];
383
224
  }
225
+ finally {
226
+ await releaseConn(conn);
227
+ }
228
+ return ret;
384
229
  };
385
230
 
386
231
  /**
@@ -404,22 +249,22 @@ SQLite.prototype.exec = async function (sql, params, timeout) {
404
249
  }
405
250
 
406
251
  this.error = null;
252
+ this.sql = '';
407
253
  let conn = null;
408
254
  timeout = timeout || this.config.query_timeout || 30000;
409
-
255
+ let ret = 0;
410
256
  try {
411
257
  // 获取连接
412
258
  conn = await this.getConn(timeout);
413
- var _this = this;
259
+ this.sql = sql;
414
260
  // 替换Promise.race为更可靠的超时控制
415
261
  let timeout_id = null;
416
-
417
- const result = await new Promise((resolve, reject) => {
262
+ ret = await new Promise((resolve, reject) => {
418
263
  // 设置超时定时器
419
264
  timeout_id = setTimeout(() => {
420
265
  reject(new Error(`SQL执行超时: ${timeout}ms`));
421
266
  }, timeout);
422
-
267
+
423
268
  // 执行SQL语句
424
269
  conn.run(sql, params || [], function (error) {
425
270
  // 清除超时定时器
@@ -427,40 +272,28 @@ SQLite.prototype.exec = async function (sql, params, timeout) {
427
272
  clearTimeout(timeout_id);
428
273
  timeout_id = null;
429
274
  }
430
-
431
275
  if (error) {
432
- _this.sql = sql;
433
- _this.error = {
434
- code: error.errno,
435
- message: error.message
436
- };
437
- // 不抛出错误,保持与MySQL一致的错误处理行为
438
- resolve(0);
276
+ reject(error);
439
277
  } else {
440
- // 保持与MySQL兼容的返回值格式
441
278
  resolve(this.lastID || this.changes || 1);
442
279
  }
443
280
  });
444
281
  });
445
-
446
- // 连接池模式下释放连接
447
- if (this._use_pool && conn) {
448
- this._releasePoolConnection(conn);
449
- }
450
-
451
- return result;
452
- } catch (err) {
453
- this.log('error', 'SQL执行失败', err);
454
-
455
- // 连接池模式下释放连接
456
- if (this._use_pool && conn) {
457
- this._releasePoolConnection(conn);
458
- }
459
-
282
+ } catch (error) {
283
+ this.log('error', 'SQL执行失败', error);
284
+ this.sql = sql;
285
+ this.error = {
286
+ code: error.errno,
287
+ message: error.message
288
+ };
460
289
  // 简化错误处理:SQLite不需要复杂的连接错误处理
461
290
  // 返回0,保持与MySQL一致的错误处理行为
462
- return 0;
291
+ ret = 0;
292
+ }
293
+ finally {
294
+ await releaseConn(conn);
463
295
  }
296
+ return ret;
464
297
  };
465
298
 
466
299
  /**
@@ -526,7 +359,7 @@ SQLite.prototype.read = async function (table, condition, options) {
526
359
  const results = await this.run(sql, params);
527
360
 
528
361
  if (this.config.debug) {
529
- this.log('info', '查询成功', { count: Array.isArray(results) ? results.length : 1 });
362
+ this.log('debug', '查询成功', { count: Array.isArray(results) ? results.length : 1 });
530
363
  }
531
364
 
532
365
  // 确保返回数组格式
@@ -592,10 +425,15 @@ SQLite.prototype.beginTrans = async function () {
592
425
  // 获取连接
593
426
  const conn = await this.getConn();
594
427
 
428
+ // 标记连接为事务中
429
+ conn._in_transaction = true;
430
+
595
431
  // 开始事务
596
432
  await new Promise((resolve, reject) => {
597
433
  conn.run('BEGIN TRANSACTION', (error) => {
598
434
  if (error) {
435
+ // 事务开始失败,清除事务标记
436
+ conn._in_transaction = false;
599
437
  reject(error);
600
438
  } else {
601
439
  resolve();
@@ -624,10 +462,9 @@ SQLite.prototype.beginTrans = async function () {
624
462
  this.log('debug', '事务提交');
625
463
  }
626
464
 
627
- // 连接池模式下释放连接
628
- if (this._use_pool) {
629
- this._releasePoolConnection(conn);
630
- }
465
+ // 清除事务标记并释放连接
466
+ conn._in_transaction = false;
467
+ await releaseConn(conn);
631
468
  },
632
469
  rollback: async () => {
633
470
  await new Promise((resolve, reject) => {
@@ -642,11 +479,9 @@ SQLite.prototype.beginTrans = async function () {
642
479
  if (this.config.debug) {
643
480
  this.log('debug', '事务回滚');
644
481
  }
645
-
646
- // 连接池模式下释放连接
647
- if (this._use_pool) {
648
- this._releasePoolConnection(conn);
649
- }
482
+ // 清除事务标记并释放连接
483
+ conn._in_transaction = false;
484
+ await releaseConn(conn);
650
485
  },
651
486
  exec: async (sql, params) => {
652
487
  // 在事务中执行SQL
@@ -737,223 +572,6 @@ SQLite.prototype.table = function (name, key) {
737
572
  return db;
738
573
  };
739
574
 
740
- /**
741
- * 创建SQLite连接
742
- * @private
743
- * @returns {Promise<object>} 数据库连接对象
744
- */
745
- SQLite.prototype._createConnection = function () {
746
- return new Promise((resolve, reject) => {
747
- const db = new sqlite3.Database(this._getDbFilename(), (err) => {
748
- if (err) {
749
- reject(err);
750
- } else {
751
- resolve(db);
752
- }
753
- });
754
- });
755
- };
756
-
757
- /**
758
- * 初始化连接池
759
- * @private
760
- * @returns {Promise<void>}
761
- */
762
- SQLite.prototype._initPool = async function () {
763
- if (this._pool_reaper) {
764
- return; // 连接池已初始化
765
- }
766
-
767
- try {
768
- // 创建最小连接数
769
- for (let i = 0; i < this.config.pool_min; i++) {
770
- const conn = await this._createConnection();
771
- this._pool_connections.push(conn);
772
- this._pool_available.push(conn);
773
- }
774
-
775
- // 启动连接回收器
776
- this._pool_reaper = setInterval(() => {
777
- this._reapIdleConnections();
778
- }, this.config.pool_reap_interval);
779
-
780
- this.log('debug', '连接池初始化完成', {
781
- min: this.config.pool_min,
782
- max: this.config.pool_max,
783
- current: this._pool_connections.length
784
- });
785
- } catch (error) {
786
- this.log('error', '连接池初始化失败', error);
787
- throw error;
788
- }
789
- };
790
-
791
- /**
792
- * 回收空闲连接
793
- * @private
794
- */
795
- SQLite.prototype._reapIdleConnections = function () {
796
- const now = Date.now();
797
- const idle_timeout = this.config.pool_idle_timeout;
798
-
799
- for (let i = this._pool_available.length - 1; i >= 0; i--) {
800
- const conn = this._pool_available[i];
801
- if (conn._last_used && now - conn._last_used > idle_timeout) {
802
- // 关闭并移除空闲连接
803
- conn.close((err) => {
804
- if (err) {
805
- this.log('error', '关闭空闲连接失败', err);
806
- }
807
- });
808
-
809
- // 从连接池中移除
810
- const conn_idx = this._pool_connections.indexOf(conn);
811
- if (conn_idx > -1) {
812
- this._pool_connections.splice(conn_idx, 1);
813
- }
814
- this._pool_available.splice(i, 1);
815
-
816
- this.log('debug', '回收空闲连接');
817
- }
818
- }
819
- };
820
-
821
- /**
822
- * 从连接池获取连接
823
- * @private
824
- * @returns {Promise<object>} 数据库连接
825
- */
826
- SQLite.prototype._getPoolConnection = async function () {
827
- const acquire_timeout = this.config.pool_acquire_timeout || 10000;
828
- const start_time = Date.now();
829
-
830
- return new Promise((resolve, reject) => {
831
- let timeout_id = null;
832
-
833
- const cleanup = () => {
834
- if (timeout_id) {
835
- clearTimeout(timeout_id);
836
- timeout_id = null;
837
- }
838
- };
839
-
840
- const tryGetConnection = () => {
841
- // 检查超时
842
- if (Date.now() - start_time > acquire_timeout) {
843
- cleanup();
844
- reject(new Error(`获取连接超时(${acquire_timeout}ms)`));
845
- return;
846
- }
847
-
848
- // 检查是否有可用连接
849
- if (this._pool_available.length > 0) {
850
- const conn = this._pool_available.shift();
851
- conn._last_used = Date.now();
852
- cleanup();
853
- resolve(conn);
854
- return;
855
- }
856
-
857
- // 检查是否可以创建新连接
858
- if (this._pool_connections.length < this.config.pool_max) {
859
- this._createConnection()
860
- .then(conn => {
861
- this._pool_connections.push(conn);
862
- conn._last_used = Date.now();
863
- cleanup();
864
- resolve(conn);
865
- })
866
- .catch(err => {
867
- cleanup();
868
- reject(err);
869
- });
870
- return;
871
- }
872
-
873
- // 没有可用连接,等待一段时间后重试(避免无限循环)
874
- timeout_id = setTimeout(tryGetConnection, 50);
875
- };
876
-
877
- tryGetConnection();
878
- });
879
- };
880
-
881
- /**
882
- * 释放连接回连接池
883
- * @private
884
- * @param {object} conn - 数据库连接
885
- */
886
- SQLite.prototype._releaseConn = function (conn) {
887
- if (this._pool_connections.includes(conn)) {
888
- conn._last_used = Date.now();
889
- this._pool_available.push(conn);
890
-
891
- // 处理等待队列
892
- if (this._pool_waiting.length > 0) {
893
- const waiting = this._pool_waiting.shift();
894
- waiting.resolve(conn);
895
- }
896
- }
897
- };
898
-
899
- /**
900
- * 释放连接池连接
901
- * @private
902
- * @param {object} conn - 数据库连接
903
- */
904
- SQLite.prototype._releasePoolConnection = function (conn) {
905
- if (!conn || !this._pool_connections.includes(conn)) {
906
- return;
907
- }
908
-
909
- // 标记连接最后使用时间
910
- conn._last_used = Date.now();
911
-
912
- // 将连接放回可用连接池
913
- if (!this._pool_available.includes(conn)) {
914
- this._pool_available.push(conn);
915
- }
916
-
917
- // 如果有等待的连接请求,立即处理
918
- if (this._pool_waiting.length > 0) {
919
- const waiting = this._pool_waiting.shift();
920
- const next_conn = this._pool_available.shift();
921
- if (next_conn && waiting.resolve) {
922
- waiting.resolve(next_conn);
923
- }
924
- }
925
- };
926
-
927
- /**
928
- * 关闭连接池
929
- * @private
930
- */
931
- SQLite.prototype._closePool = function () {
932
- if (this._pool_reaper) {
933
- clearInterval(this._pool_reaper);
934
- this._pool_reaper = null;
935
- }
936
-
937
- // 关闭所有连接
938
- this._pool_connections.forEach(conn => {
939
- try {
940
- conn.close((err) => {
941
- if (err) {
942
- this.log('error', '关闭连接池连接失败', err);
943
- }
944
- });
945
- } catch (error) {
946
- this.log('error', '关闭连接池连接异常', error);
947
- }
948
- });
949
-
950
- this._pool_connections = [];
951
- this._pool_available = [];
952
- this._pool_waiting = [];
953
-
954
- this.log('debug', '连接池已关闭');
955
- };
956
-
957
575
  /**
958
576
  * 确保连接池对象存在
959
577
  */
@@ -982,6 +600,18 @@ function sqliteAdmin(scope, config) {
982
600
  return obj;
983
601
  }
984
602
 
603
+ /**
604
+ * 安全释放数据库连接
605
+ * @param {object} conn - 数据库连接对象
606
+ * @returns {Promise<void>}
607
+ */
608
+ async function releaseConn(conn) {
609
+ if (!conn) {
610
+ return;
611
+ }
612
+ await conn.release();
613
+ }
614
+
985
615
  // 模块导出
986
616
  exports.SQLite = SQLite;
987
617
  exports.sqliteAdmin = sqliteAdmin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mm_sqlite",
3
- "version": "1.3.9",
3
+ "version": "1.4.0",
4
4
  "description": "高性能SQLite数据库操作模块,提供与mm_mysql完全兼容的API接口,支持异步操作、事务处理和批量操作",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/pool.js ADDED
@@ -0,0 +1,246 @@
1
+ const sqlite3 = require('sqlite3').verbose();
2
+
3
+ /**
4
+ * SQLite连接池类
5
+ * @class SQLitePool
6
+ */
7
+ class SQLitePool {
8
+ /**
9
+ * 构造函数
10
+ * @param {object} config - 连接池配置
11
+ * @param {function} getDbFilename - 获取数据库文件名的函数
12
+ * @param {function} log - 日志函数
13
+ */
14
+ constructor(config, getDbFilename, log) {
15
+ this.config = config;
16
+ this._getDbFilename = getDbFilename;
17
+ this.log = log;
18
+
19
+ // 连接池状态
20
+ this._pool_connections = [];
21
+ this._pool_available = [];
22
+ this._pool_waiting = [];
23
+ this._pool_reaper = null;
24
+ this._is_initialized = false;
25
+ }
26
+
27
+ /**
28
+ * 初始化连接池
29
+ * @returns {Promise<void>}
30
+ */
31
+ async init() {
32
+ if (this._is_initialized) {
33
+ return;
34
+ }
35
+
36
+ try {
37
+ // 创建最小连接数
38
+ for (let i = 0; i < this.config.pool_min; i++) {
39
+ const conn = await this._createConnection();
40
+ this._pool_connections.push(conn);
41
+ this._pool_available.push(conn);
42
+ }
43
+
44
+ // 启动连接回收器
45
+ this._pool_reaper = setInterval(() => {
46
+ this._reapIdleConnections();
47
+ }, this.config.pool_reap_interval);
48
+
49
+ this._is_initialized = true;
50
+ } catch (error) {
51
+ this.log('error', '连接池初始化失败', error);
52
+ throw error;
53
+ }
54
+ }
55
+
56
+ /**
57
+ * 获取数据库连接
58
+ * @param {number} timeout - 超时时间(毫秒)
59
+ * @returns {Promise<object>} 数据库连接
60
+ */
61
+ async getConnection(timeout) {
62
+ const acquire_timeout = timeout || this.config.pool_acquire_timeout || 10000;
63
+ const start_time = Date.now();
64
+
65
+ return new Promise((resolve, reject) => {
66
+ let timeout_id = null;
67
+
68
+ const cleanup = () => {
69
+ if (timeout_id) {
70
+ clearTimeout(timeout_id);
71
+ timeout_id = null;
72
+ }
73
+ };
74
+
75
+ const tryGetConnection = () => {
76
+ // 检查超时
77
+ if (Date.now() - start_time > acquire_timeout) {
78
+ cleanup();
79
+ reject(new Error(`获取连接超时(${acquire_timeout}ms)`));
80
+ return;
81
+ }
82
+
83
+ // 检查是否有可用连接
84
+ if (this._pool_available.length > 0) {
85
+ const conn = this._pool_available.shift();
86
+ conn._last_used = Date.now();
87
+ cleanup();
88
+ resolve(conn);
89
+ return;
90
+ }
91
+
92
+ // 检查是否可以创建新连接
93
+ if (this._pool_connections.length < this.config.pool_max) {
94
+ this._createConnection()
95
+ .then(conn => {
96
+ this._pool_connections.push(conn);
97
+ conn._last_used = Date.now();
98
+ conn.release = () => this.releaseConn(conn);
99
+ cleanup();
100
+ resolve(conn);
101
+ })
102
+ .catch(err => {
103
+ cleanup();
104
+ reject(err);
105
+ });
106
+ return;
107
+ }
108
+
109
+ // 没有可用连接且无法创建新连接,加入等待队列
110
+ this._pool_waiting.push({
111
+ resolve: (conn) => {
112
+ cleanup();
113
+ resolve(conn);
114
+ },
115
+ reject: (err) => {
116
+ cleanup();
117
+ reject(err);
118
+ }
119
+ });
120
+
121
+ // 设置重试定时器
122
+ timeout_id = setTimeout(() => {
123
+ tryGetConnection();
124
+ }, 100);
125
+ };
126
+
127
+ tryGetConnection();
128
+ });
129
+ }
130
+
131
+ /**
132
+ * 释放连接
133
+ * @param {object} conn - 数据库连接
134
+ */
135
+ releaseConn(conn) {
136
+ if (!conn || !this._pool_connections.includes(conn)) {
137
+ return;
138
+ }
139
+
140
+ // 标记连接最后使用时间
141
+ conn._last_used = Date.now();
142
+
143
+ // 将连接放回可用连接池
144
+ if (!this._pool_available.includes(conn)) {
145
+ this._pool_available.push(conn);
146
+ }
147
+
148
+ // 如果有等待的连接请求,立即处理
149
+ if (this._pool_waiting.length > 0) {
150
+ const waiting = this._pool_waiting.shift();
151
+ const next_conn = this._pool_available.shift();
152
+ if (next_conn && waiting.resolve) {
153
+ waiting.resolve(next_conn);
154
+ }
155
+ }
156
+ }
157
+
158
+ /**
159
+ * 关闭连接池
160
+ */
161
+ close() {
162
+ if (this._pool_reaper) {
163
+ clearInterval(this._pool_reaper);
164
+ this._pool_reaper = null;
165
+ }
166
+
167
+ // 关闭所有连接
168
+ this._pool_connections.forEach(conn => {
169
+ try {
170
+ conn.close((err) => {
171
+ if (err) {
172
+ this.log('error', '关闭连接池连接失败', err);
173
+ }
174
+ });
175
+ } catch (error) {
176
+ this.log('error', '关闭连接池连接异常', error);
177
+ }
178
+ });
179
+
180
+ this._pool_connections = [];
181
+ this._pool_available = [];
182
+ this._pool_waiting = [];
183
+ this._is_initialized = false;
184
+ }
185
+
186
+ /**
187
+ * 获取连接池统计信息
188
+ * @returns {object} 统计信息
189
+ */
190
+ getStats() {
191
+ return {
192
+ total: this._pool_connections.length,
193
+ available: this._pool_available.length,
194
+ waiting: this._pool_waiting.length,
195
+ is_initialized: this._is_initialized
196
+ };
197
+ }
198
+
199
+ /**
200
+ * 创建SQLite连接
201
+ * @private
202
+ * @returns {Promise<object>} 数据库连接对象
203
+ */
204
+ _createConnection() {
205
+ return new Promise((resolve, reject) => {
206
+ const db = new sqlite3.Database(this._getDbFilename(), (err) => {
207
+ if (err) {
208
+ reject(err);
209
+ } else {
210
+ db.release = () => this.releaseConn(db);
211
+ resolve(db);
212
+ }
213
+ });
214
+ });
215
+ }
216
+
217
+ /**
218
+ * 回收空闲连接
219
+ * @private
220
+ */
221
+ _reapIdleConnections() {
222
+ const now = Date.now();
223
+ const idle_timeout = this.config.pool_idle_timeout;
224
+
225
+ for (let i = this._pool_available.length - 1; i >= 0; i--) {
226
+ const conn = this._pool_available[i];
227
+ if (conn._last_used && now - conn._last_used > idle_timeout) {
228
+ // 关闭并移除空闲连接
229
+ conn.close((err) => {
230
+ if (err) {
231
+ this.log('error', '关闭空闲连接失败', err);
232
+ }
233
+ });
234
+
235
+ // 从连接池中移除
236
+ const conn_idx = this._pool_connections.indexOf(conn);
237
+ if (conn_idx > -1) {
238
+ this._pool_connections.splice(conn_idx, 1);
239
+ }
240
+ this._pool_available.splice(i, 1);
241
+ }
242
+ }
243
+ }
244
+ }
245
+
246
+ module.exports = SQLitePool;
Binary file
Binary file
Binary file