mm_sqlite 1.3.7 → 1.3.8
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/db.js +4 -4
- package/index.js +138 -86
- package/package.json +2 -2
- package/sql.js +0 -1
- package/test_db/test_basic.db +0 -0
- package/test_db/test_core_methods.db +0 -0
package/db.js
CHANGED
|
@@ -23,7 +23,7 @@ class DB extends Sql {
|
|
|
23
23
|
* 获取上级
|
|
24
24
|
* @returns {object} 返回上级管理器
|
|
25
25
|
*/
|
|
26
|
-
this.
|
|
26
|
+
this.getParent = function () {
|
|
27
27
|
return sqlite;
|
|
28
28
|
};
|
|
29
29
|
}
|
|
@@ -48,7 +48,7 @@ DB.prototype._createTimeoutPromise = function (timeout, message) {
|
|
|
48
48
|
* @returns {string} 数据库
|
|
49
49
|
*/
|
|
50
50
|
DB.prototype.database = function () {
|
|
51
|
-
return this.
|
|
51
|
+
return this.getParent().config.database;
|
|
52
52
|
};
|
|
53
53
|
|
|
54
54
|
/**
|
|
@@ -58,7 +58,7 @@ DB.prototype.database = function () {
|
|
|
58
58
|
* @returns {object} 返回管理器
|
|
59
59
|
*/
|
|
60
60
|
DB.prototype.new = function (table, key) {
|
|
61
|
-
var db = this.
|
|
61
|
+
var db = this.getParent().db();
|
|
62
62
|
db.table = table;
|
|
63
63
|
if (key) {
|
|
64
64
|
db.key = key;
|
|
@@ -77,7 +77,7 @@ DB.prototype.new = function (table, key) {
|
|
|
77
77
|
DB.prototype.getConn = async function (timeout = 15000) {
|
|
78
78
|
try {
|
|
79
79
|
// 直接使用SQLite实例的getConn方法,避免Promise.race导致的死锁
|
|
80
|
-
return await this.
|
|
80
|
+
return await this.getParent().getConn(timeout);
|
|
81
81
|
} catch (error) {
|
|
82
82
|
this.log('error', '获取连接失败', error);
|
|
83
83
|
// 重新抛出异常,因为调用方需要连接对象
|
package/index.js
CHANGED
|
@@ -21,23 +21,23 @@ class SQLite extends Base {
|
|
|
21
21
|
database: 'mm',
|
|
22
22
|
charset: 'utf8mb4',
|
|
23
23
|
timezone: '+08:00',
|
|
24
|
-
connect_timeout:
|
|
25
|
-
acquire_timeout:
|
|
26
|
-
query_timeout:
|
|
27
|
-
connection_limit:
|
|
24
|
+
connect_timeout: 5000, // 减少连接超时时间
|
|
25
|
+
acquire_timeout: 5000, // 减少获取连接超时时间
|
|
26
|
+
query_timeout: 10000, // 减少查询超时时间
|
|
27
|
+
connection_limit: 10, // 减少最大连接数
|
|
28
28
|
queue_limit: 0,
|
|
29
|
-
enable_keep_alive:
|
|
30
|
-
keep_alive_initial_delay:
|
|
31
|
-
enable_reconnect:
|
|
32
|
-
reconnect_interval:
|
|
33
|
-
max_reconnect_attempts:
|
|
34
|
-
wait_for_connections:
|
|
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
35
|
// 连接池相关配置
|
|
36
36
|
pool_min: 1,
|
|
37
|
-
pool_max:
|
|
38
|
-
pool_acquire_timeout:
|
|
39
|
-
pool_idle_timeout:
|
|
40
|
-
pool_reap_interval:
|
|
37
|
+
pool_max: 3, // 减少最大连接池大小
|
|
38
|
+
pool_acquire_timeout: 5000, // 减少连接池获取超时
|
|
39
|
+
pool_idle_timeout: 30000, // 减少空闲超时
|
|
40
|
+
pool_reap_interval: 5000 // 减少回收间隔
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
/**
|
|
@@ -46,26 +46,33 @@ class SQLite extends Base {
|
|
|
46
46
|
*/
|
|
47
47
|
constructor(config) {
|
|
48
48
|
super(config);
|
|
49
|
-
this._connection = null;
|
|
50
|
-
this._pool = null;
|
|
51
|
-
this._status = 'closed';
|
|
52
|
-
this._last_connect_time = 0;
|
|
53
|
-
this._reconnecting = false;
|
|
54
|
-
this._is_inited = false;
|
|
55
|
-
this._is_destroyed = false;
|
|
56
|
-
this._db = null;
|
|
57
|
-
this._open = false;
|
|
58
|
-
this._conn_retry_count = 0;
|
|
59
|
-
|
|
60
|
-
// 连接池相关属性
|
|
61
|
-
this._use_pool = this.config.connection_limit > 1;
|
|
62
49
|
this._pool_connections = [];
|
|
63
50
|
this._pool_available = [];
|
|
64
51
|
this._pool_waiting = [];
|
|
65
|
-
this._pool_reaper = null;
|
|
66
52
|
}
|
|
67
53
|
}
|
|
68
54
|
|
|
55
|
+
/**
|
|
56
|
+
* 预初始化数据库连接
|
|
57
|
+
* @private
|
|
58
|
+
*/
|
|
59
|
+
SQLite.prototype._preset = function () {
|
|
60
|
+
this._connection = null;
|
|
61
|
+
this._pool = null;
|
|
62
|
+
this._status = 'closed';
|
|
63
|
+
this._last_connect_time = 0;
|
|
64
|
+
this._reconnecting = false;
|
|
65
|
+
this._is_inited = false;
|
|
66
|
+
this._is_destroyed = false;
|
|
67
|
+
this._db = null;
|
|
68
|
+
this._open = false;
|
|
69
|
+
this._conn_retry_count = 0;
|
|
70
|
+
|
|
71
|
+
// 连接池相关属性
|
|
72
|
+
this._use_pool = this.config.connection_limit > 1;
|
|
73
|
+
this._pool_reaper = null;
|
|
74
|
+
};
|
|
75
|
+
|
|
69
76
|
/**
|
|
70
77
|
* 初始化服务
|
|
71
78
|
* @returns {Promise<void>}
|
|
@@ -150,16 +157,29 @@ SQLite.prototype.open = async function (timeout) {
|
|
|
150
157
|
});
|
|
151
158
|
return true;
|
|
152
159
|
} else {
|
|
153
|
-
// 使用单连接模式
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
reject(new Error(`数据库连接超时(${connect_timeout}ms)`));
|
|
158
|
-
}, connect_timeout);
|
|
159
|
-
});
|
|
160
|
-
|
|
160
|
+
// 使用单连接模式 - 替换Promise.race为更可靠的超时控制
|
|
161
|
+
let timeout_id = null;
|
|
162
|
+
let connection_success = false;
|
|
163
|
+
|
|
161
164
|
try {
|
|
162
|
-
|
|
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
|
+
}
|
|
163
183
|
|
|
164
184
|
this._last_connect_time = Date.now();
|
|
165
185
|
this._status = 'connected';
|
|
@@ -169,7 +189,13 @@ SQLite.prototype.open = async function (timeout) {
|
|
|
169
189
|
});
|
|
170
190
|
return true;
|
|
171
191
|
} catch (connection_err) {
|
|
192
|
+
// 确保超时定时器被清除
|
|
193
|
+
if (timeout_id) {
|
|
194
|
+
clearTimeout(timeout_id);
|
|
195
|
+
timeout_id = null;
|
|
196
|
+
}
|
|
172
197
|
this.log('error', '连接过程错误详情', connection_err);
|
|
198
|
+
throw connection_err;
|
|
173
199
|
}
|
|
174
200
|
}
|
|
175
201
|
} catch (err) {
|
|
@@ -248,25 +274,30 @@ SQLite.prototype.getConn = async function (timeout) {
|
|
|
248
274
|
// 从连接池获取连接
|
|
249
275
|
return await this._getPoolConnection();
|
|
250
276
|
} else {
|
|
251
|
-
// 单连接模式
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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
|
+
}
|
|
263
298
|
}
|
|
264
299
|
} catch (error) {
|
|
265
300
|
this.log('error', '获取连接失败', error);
|
|
266
|
-
|
|
267
|
-
if (error.code && (error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT')) {
|
|
268
|
-
this._handleConnectionError(error);
|
|
269
|
-
}
|
|
270
301
|
return null;
|
|
271
302
|
}
|
|
272
303
|
};
|
|
@@ -300,9 +331,23 @@ SQLite.prototype.run = async function (sql, params = [], timeout = 30000) {
|
|
|
300
331
|
conn = await this.getConn(query_timeout);
|
|
301
332
|
|
|
302
333
|
const self = this;
|
|
303
|
-
//
|
|
304
|
-
|
|
334
|
+
// 替换Promise.race为更可靠的超时控制
|
|
335
|
+
let timeout_id = null;
|
|
336
|
+
|
|
337
|
+
const result = await new Promise((resolve, reject) => {
|
|
338
|
+
// 设置超时定时器
|
|
339
|
+
timeout_id = setTimeout(() => {
|
|
340
|
+
reject(new Error(`SQL查询超时: ${timeout}ms`));
|
|
341
|
+
}, timeout);
|
|
342
|
+
|
|
343
|
+
// 执行SQL查询
|
|
305
344
|
conn.all(sql, params || [], (error, rows) => {
|
|
345
|
+
// 清除超时定时器
|
|
346
|
+
if (timeout_id) {
|
|
347
|
+
clearTimeout(timeout_id);
|
|
348
|
+
timeout_id = null;
|
|
349
|
+
}
|
|
350
|
+
|
|
306
351
|
if (error) {
|
|
307
352
|
self.sql = sql;
|
|
308
353
|
self.error = {
|
|
@@ -318,14 +363,6 @@ SQLite.prototype.run = async function (sql, params = [], timeout = 30000) {
|
|
|
318
363
|
});
|
|
319
364
|
});
|
|
320
365
|
|
|
321
|
-
const timeout_promise = new Promise((unused_resolve, reject) => {
|
|
322
|
-
setTimeout(() => {
|
|
323
|
-
reject(new Error(`SQL查询超时: ${timeout}ms`));
|
|
324
|
-
}, timeout);
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
const result = await Promise.race([query_promise, timeout_promise]);
|
|
328
|
-
|
|
329
366
|
// 连接池模式下释放连接
|
|
330
367
|
if (this._use_pool && conn) {
|
|
331
368
|
this._releasePoolConnection(conn);
|
|
@@ -340,11 +377,8 @@ SQLite.prototype.run = async function (sql, params = [], timeout = 30000) {
|
|
|
340
377
|
this._releasePoolConnection(conn);
|
|
341
378
|
}
|
|
342
379
|
|
|
343
|
-
//
|
|
344
|
-
|
|
345
|
-
this._handleConnectionError(err);
|
|
346
|
-
}
|
|
347
|
-
// 返回空数组,保持与MySQL一致的错误处理行为
|
|
380
|
+
// 简化错误处理:SQLite不需要复杂的连接错误处理
|
|
381
|
+
// 直接返回空数组,保持与MySQL一致的错误处理行为
|
|
348
382
|
return [];
|
|
349
383
|
}
|
|
350
384
|
};
|
|
@@ -377,9 +411,23 @@ SQLite.prototype.exec = async function (sql, params, timeout) {
|
|
|
377
411
|
// 获取连接
|
|
378
412
|
conn = await this.getConn(timeout);
|
|
379
413
|
var _this = this;
|
|
380
|
-
//
|
|
381
|
-
|
|
414
|
+
// 替换Promise.race为更可靠的超时控制
|
|
415
|
+
let timeout_id = null;
|
|
416
|
+
|
|
417
|
+
const result = await new Promise((resolve, reject) => {
|
|
418
|
+
// 设置超时定时器
|
|
419
|
+
timeout_id = setTimeout(() => {
|
|
420
|
+
reject(new Error(`SQL执行超时: ${timeout}ms`));
|
|
421
|
+
}, timeout);
|
|
422
|
+
|
|
423
|
+
// 执行SQL语句
|
|
382
424
|
conn.run(sql, params || [], function (error) {
|
|
425
|
+
// 清除超时定时器
|
|
426
|
+
if (timeout_id) {
|
|
427
|
+
clearTimeout(timeout_id);
|
|
428
|
+
timeout_id = null;
|
|
429
|
+
}
|
|
430
|
+
|
|
383
431
|
if (error) {
|
|
384
432
|
_this.sql = sql;
|
|
385
433
|
_this.error = {
|
|
@@ -395,14 +443,6 @@ SQLite.prototype.exec = async function (sql, params, timeout) {
|
|
|
395
443
|
});
|
|
396
444
|
});
|
|
397
445
|
|
|
398
|
-
const timeout_promise = new Promise((unused_resolve, reject) => {
|
|
399
|
-
setTimeout(() => {
|
|
400
|
-
reject(new Error(`SQL执行超时: ${timeout}ms`));
|
|
401
|
-
}, timeout);
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
const result = await Promise.race([query_promise, timeout_promise]);
|
|
405
|
-
|
|
406
446
|
// 连接池模式下释放连接
|
|
407
447
|
if (this._use_pool && conn) {
|
|
408
448
|
this._releasePoolConnection(conn);
|
|
@@ -417,10 +457,7 @@ SQLite.prototype.exec = async function (sql, params, timeout) {
|
|
|
417
457
|
this._releasePoolConnection(conn);
|
|
418
458
|
}
|
|
419
459
|
|
|
420
|
-
//
|
|
421
|
-
if (err.code && (err.code === 'ECONNRESET' || err.code === 'ETIMEDOUT')) {
|
|
422
|
-
this._handleConnectionError(err);
|
|
423
|
-
}
|
|
460
|
+
// 简化错误处理:SQLite不需要复杂的连接错误处理
|
|
424
461
|
// 返回0,保持与MySQL一致的错误处理行为
|
|
425
462
|
return 0;
|
|
426
463
|
}
|
|
@@ -787,13 +824,23 @@ SQLite.prototype._reapIdleConnections = function () {
|
|
|
787
824
|
* @returns {Promise<object>} 数据库连接
|
|
788
825
|
*/
|
|
789
826
|
SQLite.prototype._getPoolConnection = async function () {
|
|
790
|
-
const acquire_timeout = this.config.pool_acquire_timeout;
|
|
827
|
+
const acquire_timeout = this.config.pool_acquire_timeout || 10000;
|
|
791
828
|
const start_time = Date.now();
|
|
792
829
|
|
|
793
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
|
+
|
|
794
840
|
const tryGetConnection = () => {
|
|
795
841
|
// 检查超时
|
|
796
842
|
if (Date.now() - start_time > acquire_timeout) {
|
|
843
|
+
cleanup();
|
|
797
844
|
reject(new Error(`获取连接超时(${acquire_timeout}ms)`));
|
|
798
845
|
return;
|
|
799
846
|
}
|
|
@@ -802,6 +849,7 @@ SQLite.prototype._getPoolConnection = async function () {
|
|
|
802
849
|
if (this._pool_available.length > 0) {
|
|
803
850
|
const conn = this._pool_available.shift();
|
|
804
851
|
conn._last_used = Date.now();
|
|
852
|
+
cleanup();
|
|
805
853
|
resolve(conn);
|
|
806
854
|
return;
|
|
807
855
|
}
|
|
@@ -812,14 +860,18 @@ SQLite.prototype._getPoolConnection = async function () {
|
|
|
812
860
|
.then(conn => {
|
|
813
861
|
this._pool_connections.push(conn);
|
|
814
862
|
conn._last_used = Date.now();
|
|
863
|
+
cleanup();
|
|
815
864
|
resolve(conn);
|
|
816
865
|
})
|
|
817
|
-
.catch(
|
|
866
|
+
.catch(err => {
|
|
867
|
+
cleanup();
|
|
868
|
+
reject(err);
|
|
869
|
+
});
|
|
818
870
|
return;
|
|
819
871
|
}
|
|
820
872
|
|
|
821
|
-
//
|
|
822
|
-
setTimeout(tryGetConnection,
|
|
873
|
+
// 没有可用连接,等待一段时间后重试(避免无限循环)
|
|
874
|
+
timeout_id = setTimeout(tryGetConnection, 50);
|
|
823
875
|
};
|
|
824
876
|
|
|
825
877
|
tryGetConnection();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_sqlite",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.8",
|
|
4
4
|
"description": "高性能SQLite数据库操作模块,提供与mm_mysql完全兼容的API接口,支持异步操作、事务处理和批量操作",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"node": ">=14.0.0"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"mm_expand": "^2.
|
|
41
|
+
"mm_expand": "^2.2.8",
|
|
42
42
|
"sqlite3": "^6.0.1",
|
|
43
43
|
"sqlstring": "^2.3.3"
|
|
44
44
|
},
|
package/sql.js
CHANGED
package/test_db/test_basic.db
CHANGED
|
Binary file
|
|
Binary file
|