mm_sqlite 1.3.5 → 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 CHANGED
@@ -11,8 +11,6 @@ class DB extends Sql {
11
11
  */
12
12
  constructor(sqlite) {
13
13
  super(sqlite.run, sqlite.exec);
14
- // 保存sqlite实例引用
15
- this._sqlite = sqlite;
16
14
  // 事务中
17
15
  this.task = 0;
18
16
 
@@ -25,7 +23,7 @@ class DB extends Sql {
25
23
  * 获取上级
26
24
  * @returns {object} 返回上级管理器
27
25
  */
28
- this.parent = function () {
26
+ this.getParent = function () {
29
27
  return sqlite;
30
28
  };
31
29
  }
@@ -50,7 +48,7 @@ DB.prototype._createTimeoutPromise = function (timeout, message) {
50
48
  * @returns {string} 数据库
51
49
  */
52
50
  DB.prototype.database = function () {
53
- return this.parent().config.database;
51
+ return this.getParent().config.database;
54
52
  };
55
53
 
56
54
  /**
@@ -60,7 +58,7 @@ DB.prototype.database = function () {
60
58
  * @returns {object} 返回管理器
61
59
  */
62
60
  DB.prototype.new = function (table, key) {
63
- var db = this.parent().db();
61
+ var db = this.getParent().db();
64
62
  db.table = table;
65
63
  if (key) {
66
64
  db.key = key;
@@ -72,20 +70,14 @@ DB.prototype.new = function (table, key) {
72
70
  };
73
71
 
74
72
  /**
75
- * 获取数据库连接
73
+ * 获取数据库连接(修复死锁版)
76
74
  * @param {number} timeout 超时时间(毫秒)
77
75
  * @returns {Promise<object>} 数据库连接对象
78
76
  */
79
77
  DB.prototype.getConn = async function (timeout = 15000) {
80
- if (!this._sqlite) {
81
- throw new Error('SQLite实例未初始化');
82
- }
83
78
  try {
84
- // 使用Promise.race实现超时控制
85
- return await Promise.race([
86
- this._sqlite.getConn(),
87
- this._createTimeoutPromise(timeout, '获取数据库连接超时')
88
- ]);
79
+ // 直接使用SQLite实例的getConn方法,避免Promise.race导致的死锁
80
+ return await this.getParent().getConn(timeout);
89
81
  } catch (error) {
90
82
  this.log('error', '获取连接失败', error);
91
83
  // 重新抛出异常,因为调用方需要连接对象
@@ -100,7 +92,7 @@ DB.prototype.getConn = async function (timeout = 15000) {
100
92
  DB.prototype.start = async function() {
101
93
  this.task = 1;
102
94
  try {
103
- await this.exec('BEGIN;', [], 15000);
95
+ await this.exec('BEGIN;');
104
96
  // 返回事务对象
105
97
  return {
106
98
  commit: async () => {
@@ -481,7 +473,7 @@ DB.prototype.emptyTable = function (table, timeout = 15000) {
481
473
  if (!table || typeof table !== 'string') {
482
474
  throw new TypeError('table must be a valid string');
483
475
  }
484
- return this.exec('DELETE FROM `' + table + '`;', timeout);
476
+ return this.exec('DELETE FROM `' + table + '`;', [], timeout);
485
477
  };
486
478
 
487
479
  /**
@@ -572,11 +564,11 @@ DB.prototype.setField = async function (field, type, value = '', not_null = true
572
564
  } else {
573
565
  sql += ';';
574
566
  }
575
- await this.exec(sql, timeout);
567
+ await this.exec(sql, [], timeout);
576
568
 
577
569
  sql = 'UPDATE TABLE `{0}` SET `{2}` = `{1}`;';
578
570
  sql = sql.replace('{0}', this.table).replace('{1}', field).replace('{2}', new_name);
579
- var ret = await this.exec(sql, timeout);
571
+ var ret = await this.exec(sql, [], timeout);
580
572
 
581
573
  if (field !== new_name) {
582
574
  // sql = "ALTER TABLE `{0}` DROP COLUMN `{1}`;";
@@ -811,12 +803,11 @@ DB.prototype.getCreateTable = async function (table, timeout = 15000) {
811
803
  /**
812
804
  * @description 获取表数据的SQL插入语句
813
805
  * @param {string} table 表名
814
- * @param {number} batchSize 批量处理大小
815
- * @param batch_size
816
- * @param {number} timeout 超时时间(毫秒)
806
+ * @param {number} batch_size 批量处理大小
807
+ * @param {number} timeout - 超时时间(毫秒)
817
808
  * @returns {Promise | string} SQL插入语句
818
809
  */
819
- DB.prototype.getTableData = async function (table, batchSize = 100, timeout = 60000) {
810
+ DB.prototype.getTableData = async function (table, batch_size = 100, timeout = 60000) {
820
811
  if (!table) {
821
812
  throw new TypeError('table must be specified');
822
813
  }
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: 20000,
25
- acquire_timeout: 20000,
26
- query_timeout: 20000,
27
- connection_limit: 500,
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: true,
30
- keep_alive_initial_delay: 10000,
31
- enable_reconnect: true,
32
- reconnect_interval: 1000,
33
- max_reconnect_attempts: 5,
34
- wait_for_connections: true,
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: 5,
38
- pool_acquire_timeout: 30000,
39
- pool_idle_timeout: 60000,
40
- pool_reap_interval: 1000
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
- const conn_promise = this._openInternal();
155
- const timeout_promise = new Promise((unused_resolve, reject) => {
156
- setTimeout(() => {
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
- await Promise.race([conn_promise, timeout_promise]);
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
- const conn_promise = new Promise((resolve) => {
253
- resolve(this._db);
254
- });
255
- const timeout_promise = new Promise((unused_resolve, reject) => {
256
- setTimeout(() => {
257
- reject(new Error(`获取数据库连接超时(${acquire_timeout}ms)`));
258
- }, acquire_timeout);
259
- });
260
-
261
- const conn = await Promise.race([conn_promise, timeout_promise]);
262
- return conn;
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
- const query_promise = new Promise((resolve, reject) => {
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
- if (err.code && (err.code === 'ECONNRESET' || err.code === 'ETIMEDOUT')) {
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
- const query_promise = new Promise((resolve, reject) => {
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(reject);
866
+ .catch(err => {
867
+ cleanup();
868
+ reject(err);
869
+ });
818
870
  return;
819
871
  }
820
872
 
821
- // 没有可用连接,等待一段时间后重试
822
- setTimeout(tryGetConnection, 100);
873
+ // 没有可用连接,等待一段时间后重试(避免无限循环)
874
+ timeout_id = setTimeout(tryGetConnection, 50);
823
875
  };
824
876
 
825
877
  tryGetConnection();
@@ -853,15 +905,15 @@ SQLite.prototype._releasePoolConnection = function (conn) {
853
905
  if (!conn || !this._pool_connections.includes(conn)) {
854
906
  return;
855
907
  }
856
-
908
+
857
909
  // 标记连接最后使用时间
858
910
  conn._last_used = Date.now();
859
-
911
+
860
912
  // 将连接放回可用连接池
861
913
  if (!this._pool_available.includes(conn)) {
862
914
  this._pool_available.push(conn);
863
915
  }
864
-
916
+
865
917
  // 如果有等待的连接请求,立即处理
866
918
  if (this._pool_waiting.length > 0) {
867
919
  const waiting = this._pool_waiting.shift();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mm_sqlite",
3
- "version": "1.3.5",
3
+ "version": "1.3.8",
4
4
  "description": "高性能SQLite数据库操作模块,提供与mm_mysql完全兼容的API接口,支持异步操作、事务处理和批量操作",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -38,12 +38,12 @@
38
38
  "node": ">=14.0.0"
39
39
  },
40
40
  "dependencies": {
41
- "mm_expand": "^2.0.2",
41
+ "mm_expand": "^2.2.8",
42
42
  "sqlite3": "^6.0.1",
43
43
  "sqlstring": "^2.3.3"
44
44
  },
45
45
  "devDependencies": {
46
- "eslint": "^10.1.0",
46
+ "eslint": "^10.2.0",
47
47
  "eslint-plugin-jsdoc": "^62.9.0",
48
48
  "mm_eslint": "^1.7.1"
49
49
  }
package/sql.js CHANGED
@@ -897,7 +897,6 @@ Sql.prototype.del = async function (query, like) {
897
897
  var sql = this.toDelSql(query, like);
898
898
  this.sql = sql;
899
899
  var bl = await this.exec(sql);
900
-
901
900
  return bl;
902
901
  } catch (err) {
903
902
  this.error = err.message;
@@ -932,34 +931,23 @@ Sql.prototype.set = async function (query, body, like) {
932
931
  };
933
932
 
934
933
  /**
935
- * @description 查询数据
934
+ * @description 查询数据(优化版)
936
935
  * @param {object} query 查询条件
937
936
  * @param {string} sort 排序
938
937
  * @param {string} view 返回的字段
939
938
  * @param {boolean} like 是否使用like匹配, 为空使用默认方式
940
- * @param {number} timeout 超时时间(毫秒),默认30000ms
939
+ * @param {number} timeout 超时时间(毫秒),默认5000ms
941
940
  * @returns {Promise|Array} 查询结果
942
941
  */
943
- Sql.prototype.get = async function (query, sort, view, like, timeout = 30000) {
942
+ Sql.prototype.get = async function (query, sort, view, like, timeout = 5000) {
944
943
  if (!this.table) {
945
944
  throw new Error('表名未设置');
946
945
  }
947
946
 
948
947
  try {
949
- // 使用Promise.race实现超时控制
950
- const timeout_promise = new Promise((unused_resolve, reject) => {
951
- setTimeout(() => reject(new Error('查询操作超时')), timeout);
952
- });
953
-
954
- return await Promise.race([
955
- (async () => {
956
- // 生成SQL并执行
957
- var sql = this.toGetSql(query, sort, view, like);
958
- var list = await this.run(sql);
959
- return list;
960
- })(),
961
- timeout_promise
962
- ]);
948
+ var sql = this.toGetSql(query, sort, view, like);
949
+ var list = await this.run(sql, [], timeout);
950
+ return list;
963
951
  } catch (err) {
964
952
  this.error = err.message;
965
953
  this.log('error', '查询数据失败', err);
@@ -1044,24 +1032,13 @@ Sql.prototype.count = async function (query, like, timeout = 30000) {
1044
1032
  }
1045
1033
 
1046
1034
  try {
1047
- // 添加超时控制
1048
- const timeout_promise = new Promise((unused_resolve, reject) => {
1049
- setTimeout(() => reject(new Error('统计操作超时')), timeout);
1050
- });
1051
-
1052
- return await Promise.race([
1053
- (async () => {
1054
- // 正确生成count SQL
1055
- const where = typeof query === 'string' ? query : await this.toWhere(query, like);
1056
- const sql = 'SELECT COUNT(*) as num FROM `' + this.table + '`' + (where ? ' WHERE ' + where : '');
1057
- this.sql = sql;
1058
- const list = await this.run(sql);
1059
- const total = list && list[0] && list[0].num ? parseInt(list[0].num) : 0;
1060
-
1061
- return total;
1062
- })(),
1063
- timeout_promise
1064
- ]);
1035
+ const where = typeof query === 'string' ? query : await this.toWhere(query, like);
1036
+ const sql = 'SELECT COUNT(*) as num FROM `' + this.table + '`' + (where ? ' WHERE ' + where : '');
1037
+ this.sql = sql;
1038
+ const list = await this.run(sql);
1039
+ const total = list && list[0] && list[0].num ? parseInt(list[0].num) : 0;
1040
+
1041
+ return total;
1065
1042
  } catch (err) {
1066
1043
  this.error = err.message;
1067
1044
  this.log('error', '统计记录数失败', err);
@@ -1094,48 +1071,31 @@ Sql.prototype.addList = async function (list, batch_size = 100, timeout = 60000)
1094
1071
  throw new Error('表名或数据列表未设置');
1095
1072
  }
1096
1073
  try {
1097
- // 添加整体操作超时控制
1098
- const timeout_promise = new Promise((unused_resolve, reject) => {
1099
- setTimeout(() => reject(new Error('批量添加数据操作超时')), timeout);
1100
- });
1101
-
1102
- return await Promise.race([
1103
- (async () => {
1104
- // 如果数据量较小,直接处理
1105
- if (list.length <= batch_size) {
1106
- // 使用批量插入语法,不使用事务包装
1107
- this.sql = this.toBatchAddSql(list);
1108
- return await this.exec(this.sql);
1109
- }
1074
+ if (list.length <= batch_size) {
1075
+ // 使用批量插入语法,不使用事务包装
1076
+ this.sql = this.toBatchAddSql(list);
1077
+ return await this.exec(this.sql);
1078
+ }
1110
1079
 
1111
- // 分批处理大数据量
1112
- const total = Math.ceil(list.length / batch_size);
1113
- this.log('info', `开始分批添加数据,共${total}批,每批${batch_size}条`);
1114
-
1115
- // 分批执行,每批一个单独的批量插入语句
1116
- let final_res = null;
1117
- for (let i = 0; i < total; i++) {
1118
- const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1119
- this.log('debug', `处理第${i + 1}/${total}批数据,${batch.length}条`);
1120
-
1121
- // 生成批量插入SQL
1122
- const batch_sql = this.toBatchAddSql(batch);
1123
- this.sql = batch_sql;
1124
-
1125
- // 为每批操作添加超时控制
1126
- final_res = await Promise.race([
1127
- this.exec(batch_sql),
1128
- new Promise((unused_resolve, reject) => {
1129
- setTimeout(() => reject(new Error(`第${i + 1}批数据处理超时`)), timeout / total);
1130
- })
1131
- ]);
1132
- }
1080
+ // 分批处理大数据量
1081
+ const total = Math.ceil(list.length / batch_size);
1082
+ this.log('info', `开始分批添加数据,共${total}批,每批${batch_size}条`);
1083
+
1084
+ // 分批执行,每批一个单独的批量插入语句
1085
+ let final_res = null;
1086
+ for (let i = 0; i < total; i++) {
1087
+ const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1088
+ this.log('debug', `处理第${i + 1}/${total}批数据,${batch.length}条`);
1133
1089
 
1134
- this.log('success', `批量添加数据完成,共${list.length}条`);
1135
- return final_res;
1136
- })(),
1137
- timeout_promise
1138
- ]);
1090
+ // 生成批量插入SQL
1091
+ const batch_sql = this.toBatchAddSql(batch);
1092
+ this.sql = batch_sql;
1093
+
1094
+ final_res = await this.exec(batch_sql);
1095
+ }
1096
+
1097
+ this.log('success', `批量添加数据完成,共${list.length}条`);
1098
+ return final_res;
1139
1099
  } catch (error) {
1140
1100
  this.log('error', '批量添加数据失败', error);
1141
1101
  // 返回默认操作结果对象,保持返回值类型一致
@@ -1197,71 +1157,53 @@ Sql.prototype.delList = async function (list, like, batch_size = 100, timeout =
1197
1157
  throw new Error('表名或数据列表未设置');
1198
1158
  }
1199
1159
  try {
1200
- // 添加整体操作超时控制
1201
- const timeout_promise = new Promise((unused_resolve, reject) => {
1202
- setTimeout(() => reject(new Error('批量删除数据操作超时')), timeout);
1203
- });
1204
-
1205
- return await Promise.race([
1206
- (async () => {
1207
- // 如果数据量较小,直接处理
1208
- if (list.length <= batch_size) {
1209
- let sql = '';
1210
- for (const item of list) {
1211
- sql += this.toDelSql(item.query, like);
1212
- }
1213
- this.sql = sql;
1214
- return await this.exec(sql);
1215
- }
1216
-
1217
- // 分批处理大数据量
1218
- const total = Math.ceil(list.length / batch_size);
1219
- this.log('info', `开始分批删除数据,共${total}批,每批${batch_size}条`);
1220
-
1221
- // 使用事务包装整个操作以保证原子性
1222
- let final_res = null;
1223
- try {
1224
- // 开始事务
1225
- await this.exec('BEGIN;', 15000);
1160
+ if (list.length <= batch_size) {
1161
+ let sql = '';
1162
+ for (const item of list) {
1163
+ sql += this.toDelSql(item.query, like);
1164
+ }
1165
+ this.sql = sql;
1166
+ return await this.exec(sql, [], timeout);
1167
+ }
1226
1168
 
1227
- // 分批处理
1228
- for (let i = 0; i < total; i++) {
1229
- const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1230
- this.log('debug', `处理第${i + 1}/${total}批数据,${batch.length}条`);
1169
+ // 分批处理大数据量
1170
+ const total = Math.ceil(list.length / batch_size);
1171
+ this.log('info', `开始分批删除数据,共${total}批,每批${batch_size}条`);
1231
1172
 
1232
- let batch_sql = '';
1233
- for (const item of batch) {
1234
- batch_sql += this.toDelSql(item.query, like);
1235
- }
1173
+ // 使用事务包装整个操作以保证原子性
1174
+ let final_res = null;
1175
+ try {
1176
+ // 开始事务
1177
+ await this.exec('BEGIN;');
1236
1178
 
1237
- // 为每批操作添加超时控制
1238
- final_res = await Promise.race([
1239
- this.exec(batch_sql),
1240
- new Promise((unused_resolve, reject) => {
1241
- setTimeout(() => reject(new Error(`第${i + 1}批数据删除超时`)), timeout / total);
1242
- })
1243
- ]);
1244
- }
1179
+ // 分批处理
1180
+ for (let i = 0; i < total; i++) {
1181
+ const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1182
+ this.log('debug', `处理第${i + 1}/${total}批数据,${batch.length}条`);
1245
1183
 
1246
- // 提交事务
1247
- await this.exec('COMMIT;', 15000);
1248
- } catch (error) {
1249
- // 发生错误时回滚事务
1250
- try {
1251
- await this.exec('ROLLBACK;', 15000);
1252
- this.log('error', '批量删除数据失败,事务已回滚', error);
1253
- } catch (rollback_err) {
1254
- this.log('error', '批量删除数据失败,事务回滚也失败', rollback_err);
1255
- }
1256
- // 记录错误日志
1257
- this.log('error', 'SQL语句执行失败', error);
1184
+ let batch_sql = '';
1185
+ for (const item of batch) {
1186
+ batch_sql += this.toDelSql(item.query, like);
1258
1187
  }
1188
+ final_res = await this.exec(batch_sql, [], timeout);
1189
+ }
1259
1190
 
1260
- this.log('success', `批量删除数据完成,共${list.length}条`);
1261
- return final_res;
1262
- })(),
1263
- timeout_promise
1264
- ]);
1191
+ // 提交事务
1192
+ await this.exec('COMMIT;', [], timeout);
1193
+ } catch (error) {
1194
+ // 发生错误时回滚事务
1195
+ try {
1196
+ await this.exec('ROLLBACK;', [], timeout);
1197
+ this.log('error', '批量删除数据失败,事务已回滚', error);
1198
+ } catch (rollback_err) {
1199
+ this.log('error', '批量删除数据失败,事务回滚也失败', rollback_err);
1200
+ }
1201
+ // 记录错误日志
1202
+ this.log('error', 'SQL语句执行失败', error);
1203
+ }
1204
+
1205
+ this.log('success', `批量删除数据完成,共${list.length}条`);
1206
+ return final_res;
1265
1207
  } catch (err) {
1266
1208
  this.log('error', '批量删除数据失败', err);
1267
1209
  // 返回默认操作结果对象,保持返回值类型一致
@@ -1281,69 +1223,52 @@ Sql.prototype.setList = async function (list, like = false, batch_size = 100, ti
1281
1223
  throw new Error('表名或数据列表未设置');
1282
1224
  }
1283
1225
  try {
1284
- // 添加整体操作超时控制
1285
- const timeout_promise = new Promise((unused_resolve, reject) => {
1286
- setTimeout(() => reject(new Error('批量更新数据操作超时')), timeout);
1287
- });
1288
-
1289
- return await Promise.race([
1290
- (async () => {
1291
- // 如果数据量较小,直接处理
1292
- if (list.length <= batch_size) {
1293
- let sql = '';
1294
- for (const item of list) {
1295
- sql += this.toSetSql(item.query, item.obj, like);
1296
- }
1297
- this.sql = sql;
1298
- return await this.exec(sql);
1299
- }
1226
+ if (list.length <= batch_size) {
1227
+ let sql = '';
1228
+ for (const item of list) {
1229
+ sql += this.toSetSql(item.query, item.obj, like);
1230
+ }
1231
+ this.sql = sql;
1232
+ return await this.exec(sql, [], timeout);
1233
+ }
1300
1234
 
1301
- // 分批处理大数据量
1302
- const total = Math.ceil(list.length / batch_size);
1303
- this.log('info', `开始分批更新数据,共${total}批,每批${batch_size}条`);
1235
+ // 分批处理大数据量
1236
+ const total = Math.ceil(list.length / batch_size);
1237
+ this.log('info', `开始分批更新数据,共${total}批,每批${batch_size}条`);
1304
1238
 
1305
- // 使用事务包装整个操作以保证原子性
1306
- let final_res = null;
1307
- try {
1308
- // 开始事务
1309
- await this.exec('BEGIN;', 15000);
1239
+ // 使用事务包装整个操作以保证原子性
1240
+ let final_res = null;
1241
+ try {
1242
+ // 开始事务
1243
+ await this.exec('BEGIN;');
1310
1244
 
1311
- // 分批处理
1312
- for (let i = 0; i < total; i++) {
1313
- const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1314
- this.log('debug', `处理第${i + 1}/${total}批数据,${batch.length}条`);
1245
+ // 分批处理
1246
+ for (let i = 0; i < total; i++) {
1247
+ const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1248
+ this.log('debug', `处理第${i + 1}/${total}批数据,${batch.length}条`);
1315
1249
 
1316
- let batch_sql = '';
1317
- for (const item of batch) {
1318
- batch_sql += this.toSetSql(item.query, item.obj, like);
1319
- }
1250
+ let batch_sql = '';
1251
+ for (const item of batch) {
1252
+ batch_sql += this.toSetSql(item.query, item.obj, like);
1253
+ }
1320
1254
 
1321
- // 为每批操作添加超时控制
1322
- final_res = await Promise.race([
1323
- this.exec(batch_sql),
1324
- new Promise((unused_resolve, reject) => {
1325
- setTimeout(() => reject(new Error(`第${i + 1}批数据更新超时`)), timeout / total);
1326
- })
1327
- ]);
1328
- }
1255
+ final_res = await this.exec(batch_sql, [], timeout);
1256
+ }
1329
1257
 
1330
- // 提交事务
1331
- await this.exec('COMMIT;', 15000);
1332
- } catch (error) {
1333
- // 发生错误时回滚事务
1334
- try {
1335
- await this.exec('ROLLBACK;', 15000);
1336
- this.log('error', '批量更新数据失败,事务已回滚', error);
1337
- } catch (rollback_err) {
1338
- this.log('error', '批量更新数据失败,事务回滚也失败', rollback_err);
1339
- }
1340
- }
1258
+ // 提交事务
1259
+ await this.exec('COMMIT;', [], timeout);
1260
+ } catch (error) {
1261
+ // 发生错误时回滚事务
1262
+ try {
1263
+ await this.exec('ROLLBACK;', [], timeout);
1264
+ this.log('error', '批量更新数据失败,事务已回滚', error);
1265
+ } catch (rollback_err) {
1266
+ this.log('error', '批量更新数据失败,事务回滚也失败', rollback_err);
1267
+ }
1268
+ }
1341
1269
 
1342
- this.log('success', `批量更新数据完成,共${list.length}条`);
1343
- return final_res;
1344
- })(),
1345
- timeout_promise
1346
- ]);
1270
+ this.log('success', `批量更新数据完成,共${list.length}条`);
1271
+ return final_res;
1347
1272
  } catch (err) {
1348
1273
  this.log('error', '批量更新数据失败', err);
1349
1274
  // 返回默认操作结果对象,保持返回值类型一致
Binary file
Binary file
Binary file
Binary file
Binary file