mm_sqlite 1.3.4 → 1.3.7

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
 
@@ -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.parent().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 () => {
@@ -265,7 +257,7 @@ DB.prototype.fields = async function (table, field_name, timeout = 15000) {
265
257
  var len = list.length;
266
258
  for (var i = 0; i < len; i++) {
267
259
  list[i].pk = list[i].pk ? true : false;
268
- list[i].notnull = list[i].notnull ? true : false;
260
+ list[i].not_null = list[i].not_null ? true : false;
269
261
  }
270
262
 
271
263
  // 如果指定了字段名,过滤结果
@@ -273,7 +265,16 @@ DB.prototype.fields = async function (table, field_name, timeout = 15000) {
273
265
  list = list.filter(field => field.name === field_name);
274
266
  }
275
267
 
276
- return list;
268
+ return list.map(item => ({
269
+ name: item.name,
270
+ cid: item.cid,
271
+ default_value: item.dflt_value,
272
+ not_null: item.notnull,
273
+ type: item.type,
274
+ pk: item.pk,
275
+ auto: item.auto,
276
+ note: item.note
277
+ }));
277
278
  } catch (err) {
278
279
  this.log('error', '获取字段信息失败', err);
279
280
  return [];
@@ -472,7 +473,7 @@ DB.prototype.emptyTable = function (table, timeout = 15000) {
472
473
  if (!table || typeof table !== 'string') {
473
474
  throw new TypeError('table must be a valid string');
474
475
  }
475
- return this.exec('DELETE FROM `' + table + '`;', timeout);
476
+ return this.exec('DELETE FROM `' + table + '`;', [], timeout);
476
477
  };
477
478
 
478
479
  /**
@@ -563,11 +564,11 @@ DB.prototype.setField = async function (field, type, value = '', not_null = true
563
564
  } else {
564
565
  sql += ';';
565
566
  }
566
- await this.exec(sql, timeout);
567
+ await this.exec(sql, [], timeout);
567
568
 
568
569
  sql = 'UPDATE TABLE `{0}` SET `{2}` = `{1}`;';
569
570
  sql = sql.replace('{0}', this.table).replace('{1}', field).replace('{2}', new_name);
570
- var ret = await this.exec(sql, timeout);
571
+ var ret = await this.exec(sql, [], timeout);
571
572
 
572
573
  if (field !== new_name) {
573
574
  // sql = "ALTER TABLE `{0}` DROP COLUMN `{1}`;";
@@ -611,22 +612,22 @@ DB.prototype.delField = async function (table, field, timeout = 15000) {
611
612
  DB.prototype.sqlField = function (fd) {
612
613
  var sql = '`{0}`'.replace('{0}', fd.name);
613
614
  sql += ' ' + fd.type;
614
- if (fd.notnull) {
615
+ if (fd.not_null) {
615
616
  sql += ' NOT NULL';
616
617
  }
617
618
  if (fd.auto) {
618
- if (fd.dflt_value) {
619
- if (fd.dflt_value === '0000-00-00 00:00:00') {
620
- fd.dflt_value = 'CURRENT_TIMESTAMP';
619
+ if (fd.default_value) {
620
+ if (fd.default_value === '0000-00-00 00:00:00') {
621
+ fd.default_value = 'CURRENT_TIMESTAMP';
621
622
  }
622
- sql += ' DEFAULT ' + fd.dflt_value;
623
+ sql += ' DEFAULT ' + fd.default_value;
623
624
  }
624
625
  sql += ' ' + fd.auto;
625
- } else if (fd.dflt_value) {
626
- if (fd.dflt_value === '0000-00-00 00:00:00') {
627
- fd.dflt_value = '1970-01-01 00:00:00';
626
+ } else if (fd.default_value) {
627
+ if (fd.default_value === '0000-00-00 00:00:00') {
628
+ fd.default_value = '1970-01-01 00:00:00';
628
629
  }
629
- sql += ' DEFAULT ' + fd.dflt_value;
630
+ sql += ' DEFAULT ' + fd.default_value;
630
631
  }
631
632
  if (fd.note) {
632
633
  sql += " COMMENT '" + fd.note + "'";
@@ -802,12 +803,11 @@ DB.prototype.getCreateTable = async function (table, timeout = 15000) {
802
803
  /**
803
804
  * @description 获取表数据的SQL插入语句
804
805
  * @param {string} table 表名
805
- * @param {number} batchSize 批量处理大小
806
- * @param batch_size
807
- * @param {number} timeout 超时时间(毫秒)
806
+ * @param {number} batch_size 批量处理大小
807
+ * @param {number} timeout - 超时时间(毫秒)
808
808
  * @returns {Promise | string} SQL插入语句
809
809
  */
810
- DB.prototype.getTableData = async function (table, batchSize = 100, timeout = 60000) {
810
+ DB.prototype.getTableData = async function (table, batch_size = 100, timeout = 60000) {
811
811
  if (!table) {
812
812
  throw new TypeError('table must be specified');
813
813
  }
package/index.js CHANGED
@@ -853,15 +853,15 @@ SQLite.prototype._releasePoolConnection = function (conn) {
853
853
  if (!conn || !this._pool_connections.includes(conn)) {
854
854
  return;
855
855
  }
856
-
856
+
857
857
  // 标记连接最后使用时间
858
858
  conn._last_used = Date.now();
859
-
859
+
860
860
  // 将连接放回可用连接池
861
861
  if (!this._pool_available.includes(conn)) {
862
862
  this._pool_available.push(conn);
863
863
  }
864
-
864
+
865
865
  // 如果有等待的连接请求,立即处理
866
866
  if (this._pool_waiting.length > 0) {
867
867
  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.4",
3
+ "version": "1.3.7",
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.1.9",
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
@@ -932,34 +932,23 @@ Sql.prototype.set = async function (query, body, like) {
932
932
  };
933
933
 
934
934
  /**
935
- * @description 查询数据
935
+ * @description 查询数据(优化版)
936
936
  * @param {object} query 查询条件
937
937
  * @param {string} sort 排序
938
938
  * @param {string} view 返回的字段
939
939
  * @param {boolean} like 是否使用like匹配, 为空使用默认方式
940
- * @param {number} timeout 超时时间(毫秒),默认30000ms
940
+ * @param {number} timeout 超时时间(毫秒),默认5000ms
941
941
  * @returns {Promise|Array} 查询结果
942
942
  */
943
- Sql.prototype.get = async function (query, sort, view, like, timeout = 30000) {
943
+ Sql.prototype.get = async function (query, sort, view, like, timeout = 5000) {
944
944
  if (!this.table) {
945
945
  throw new Error('表名未设置');
946
946
  }
947
947
 
948
948
  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
- ]);
949
+ var sql = this.toGetSql(query, sort, view, like);
950
+ var list = await this.run(sql, [], timeout);
951
+ return list;
963
952
  } catch (err) {
964
953
  this.error = err.message;
965
954
  this.log('error', '查询数据失败', err);
@@ -1044,24 +1033,13 @@ Sql.prototype.count = async function (query, like, timeout = 30000) {
1044
1033
  }
1045
1034
 
1046
1035
  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
- ]);
1036
+ const where = typeof query === 'string' ? query : await this.toWhere(query, like);
1037
+ const sql = 'SELECT COUNT(*) as num FROM `' + this.table + '`' + (where ? ' WHERE ' + where : '');
1038
+ this.sql = sql;
1039
+ const list = await this.run(sql);
1040
+ const total = list && list[0] && list[0].num ? parseInt(list[0].num) : 0;
1041
+
1042
+ return total;
1065
1043
  } catch (err) {
1066
1044
  this.error = err.message;
1067
1045
  this.log('error', '统计记录数失败', err);
@@ -1094,48 +1072,31 @@ Sql.prototype.addList = async function (list, batch_size = 100, timeout = 60000)
1094
1072
  throw new Error('表名或数据列表未设置');
1095
1073
  }
1096
1074
  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
- }
1075
+ if (list.length <= batch_size) {
1076
+ // 使用批量插入语法,不使用事务包装
1077
+ this.sql = this.toBatchAddSql(list);
1078
+ return await this.exec(this.sql);
1079
+ }
1110
1080
 
1111
- // 分批处理大数据量
1112
- const total = Math.ceil(list.length / batch_size);
1113
- $.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
- $.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
- }
1081
+ // 分批处理大数据量
1082
+ const total = Math.ceil(list.length / batch_size);
1083
+ this.log('info', `开始分批添加数据,共${total}批,每批${batch_size}条`);
1084
+
1085
+ // 分批执行,每批一个单独的批量插入语句
1086
+ let final_res = null;
1087
+ for (let i = 0; i < total; i++) {
1088
+ const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1089
+ this.log('debug', `处理第${i + 1}/${total}批数据,${batch.length}条`);
1090
+
1091
+ // 生成批量插入SQL
1092
+ const batch_sql = this.toBatchAddSql(batch);
1093
+ this.sql = batch_sql;
1094
+
1095
+ final_res = await this.exec(batch_sql);
1096
+ }
1133
1097
 
1134
- $.log.success(`批量添加数据完成,共${list.length}条`);
1135
- return final_res;
1136
- })(),
1137
- timeout_promise
1138
- ]);
1098
+ this.log('success', `批量添加数据完成,共${list.length}条`);
1099
+ return final_res;
1139
1100
  } catch (error) {
1140
1101
  this.log('error', '批量添加数据失败', error);
1141
1102
  // 返回默认操作结果对象,保持返回值类型一致
@@ -1197,71 +1158,53 @@ Sql.prototype.delList = async function (list, like, batch_size = 100, timeout =
1197
1158
  throw new Error('表名或数据列表未设置');
1198
1159
  }
1199
1160
  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
- $.log.info(`开始分批删除数据,共${total}批,每批${batch_size}条`);
1220
-
1221
- // 使用事务包装整个操作以保证原子性
1222
- let final_res = null;
1223
- try {
1224
- // 开始事务
1225
- await this.exec('BEGIN;', 15000);
1161
+ if (list.length <= batch_size) {
1162
+ let sql = '';
1163
+ for (const item of list) {
1164
+ sql += this.toDelSql(item.query, like);
1165
+ }
1166
+ this.sql = sql;
1167
+ return await this.exec(sql, [], timeout);
1168
+ }
1226
1169
 
1227
- // 分批处理
1228
- for (let i = 0; i < total; i++) {
1229
- const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1230
- $.log.debug(`处理第${i + 1}/${total}批数据,${batch.length}条`);
1170
+ // 分批处理大数据量
1171
+ const total = Math.ceil(list.length / batch_size);
1172
+ this.log('info', `开始分批删除数据,共${total}批,每批${batch_size}条`);
1231
1173
 
1232
- let batch_sql = '';
1233
- for (const item of batch) {
1234
- batch_sql += this.toDelSql(item.query, like);
1235
- }
1174
+ // 使用事务包装整个操作以保证原子性
1175
+ let final_res = null;
1176
+ try {
1177
+ // 开始事务
1178
+ await this.exec('BEGIN;');
1236
1179
 
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
- }
1180
+ // 分批处理
1181
+ for (let i = 0; i < total; i++) {
1182
+ const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1183
+ this.log('debug', `处理第${i + 1}/${total}批数据,${batch.length}条`);
1245
1184
 
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);
1185
+ let batch_sql = '';
1186
+ for (const item of batch) {
1187
+ batch_sql += this.toDelSql(item.query, like);
1258
1188
  }
1189
+ final_res = await this.exec(batch_sql, [], timeout);
1190
+ }
1191
+
1192
+ // 提交事务
1193
+ await this.exec('COMMIT;', [], timeout);
1194
+ } catch (error) {
1195
+ // 发生错误时回滚事务
1196
+ try {
1197
+ await this.exec('ROLLBACK;', [], timeout);
1198
+ this.log('error', '批量删除数据失败,事务已回滚', error);
1199
+ } catch (rollback_err) {
1200
+ this.log('error', '批量删除数据失败,事务回滚也失败', rollback_err);
1201
+ }
1202
+ // 记录错误日志
1203
+ this.log('error', 'SQL语句执行失败', error);
1204
+ }
1259
1205
 
1260
- $.log.success(`批量删除数据完成,共${list.length}条`);
1261
- return final_res;
1262
- })(),
1263
- timeout_promise
1264
- ]);
1206
+ this.log('success', `批量删除数据完成,共${list.length}条`);
1207
+ return final_res;
1265
1208
  } catch (err) {
1266
1209
  this.log('error', '批量删除数据失败', err);
1267
1210
  // 返回默认操作结果对象,保持返回值类型一致
@@ -1281,69 +1224,52 @@ Sql.prototype.setList = async function (list, like = false, batch_size = 100, ti
1281
1224
  throw new Error('表名或数据列表未设置');
1282
1225
  }
1283
1226
  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
- }
1227
+ if (list.length <= batch_size) {
1228
+ let sql = '';
1229
+ for (const item of list) {
1230
+ sql += this.toSetSql(item.query, item.obj, like);
1231
+ }
1232
+ this.sql = sql;
1233
+ return await this.exec(sql, [], timeout);
1234
+ }
1300
1235
 
1301
- // 分批处理大数据量
1302
- const total = Math.ceil(list.length / batch_size);
1303
- $.log.info(`开始分批更新数据,共${total}批,每批${batch_size}条`);
1236
+ // 分批处理大数据量
1237
+ const total = Math.ceil(list.length / batch_size);
1238
+ this.log('info', `开始分批更新数据,共${total}批,每批${batch_size}条`);
1304
1239
 
1305
- // 使用事务包装整个操作以保证原子性
1306
- let final_res = null;
1307
- try {
1308
- // 开始事务
1309
- await this.exec('BEGIN;', 15000);
1240
+ // 使用事务包装整个操作以保证原子性
1241
+ let final_res = null;
1242
+ try {
1243
+ // 开始事务
1244
+ await this.exec('BEGIN;');
1310
1245
 
1311
- // 分批处理
1312
- for (let i = 0; i < total; i++) {
1313
- const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1314
- $.log.debug(`处理第${i + 1}/${total}批数据,${batch.length}条`);
1246
+ // 分批处理
1247
+ for (let i = 0; i < total; i++) {
1248
+ const batch = list.slice(i * batch_size, (i + 1) * batch_size);
1249
+ this.log('debug', `处理第${i + 1}/${total}批数据,${batch.length}条`);
1315
1250
 
1316
- let batch_sql = '';
1317
- for (const item of batch) {
1318
- batch_sql += this.toSetSql(item.query, item.obj, like);
1319
- }
1251
+ let batch_sql = '';
1252
+ for (const item of batch) {
1253
+ batch_sql += this.toSetSql(item.query, item.obj, like);
1254
+ }
1320
1255
 
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
- }
1256
+ final_res = await this.exec(batch_sql, [], timeout);
1257
+ }
1329
1258
 
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
- }
1259
+ // 提交事务
1260
+ await this.exec('COMMIT;', [], timeout);
1261
+ } catch (error) {
1262
+ // 发生错误时回滚事务
1263
+ try {
1264
+ await this.exec('ROLLBACK;', [], timeout);
1265
+ this.log('error', '批量更新数据失败,事务已回滚', error);
1266
+ } catch (rollback_err) {
1267
+ this.log('error', '批量更新数据失败,事务回滚也失败', rollback_err);
1268
+ }
1269
+ }
1341
1270
 
1342
- $.log.success(`批量更新数据完成,共${list.length}条`);
1343
- return final_res;
1344
- })(),
1345
- timeout_promise
1346
- ]);
1271
+ this.log('success', `批量更新数据完成,共${list.length}条`);
1272
+ return final_res;
1347
1273
  } catch (err) {
1348
1274
  this.log('error', '批量更新数据失败', err);
1349
1275
  // 返回默认操作结果对象,保持返回值类型一致
Binary file
Binary file
Binary file
Binary file
Binary file