mm_mysql 2.3.4 → 2.3.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.
- package/db.js +14 -16
- package/package.json +1 -1
- package/sql.js +115 -166
package/db.js
CHANGED
|
@@ -17,8 +17,6 @@ class DB extends Sql {
|
|
|
17
17
|
mysql.run,
|
|
18
18
|
mysql.exec
|
|
19
19
|
);
|
|
20
|
-
// 保存mysql实例引用
|
|
21
|
-
this._mysql = mysql;
|
|
22
20
|
// 事务中
|
|
23
21
|
this.task = 0;
|
|
24
22
|
|
|
@@ -82,7 +80,7 @@ DB.prototype.new = function (table, key) {
|
|
|
82
80
|
*/
|
|
83
81
|
DB.prototype.getConn = async function() {
|
|
84
82
|
try {
|
|
85
|
-
return await this.
|
|
83
|
+
return await this.parent().getConn();
|
|
86
84
|
} catch (error) {
|
|
87
85
|
this.log('error', '获取连接失败', error);
|
|
88
86
|
// 返回null作为默认值,保持返回值类型一致
|
|
@@ -96,7 +94,7 @@ DB.prototype.getConn = async function() {
|
|
|
96
94
|
*/
|
|
97
95
|
DB.prototype.start = async function() {
|
|
98
96
|
try {
|
|
99
|
-
return await this.
|
|
97
|
+
return await this.parent().beginTransaction();
|
|
100
98
|
} catch (error) {
|
|
101
99
|
this.log('error', '开始事务失败', error);
|
|
102
100
|
// 返回null作为默认值,保持返回值类型一致
|
|
@@ -155,7 +153,7 @@ DB.prototype.transaction = async function(callback) {
|
|
|
155
153
|
}
|
|
156
154
|
|
|
157
155
|
try {
|
|
158
|
-
return await this.
|
|
156
|
+
return await this.parent().transaction(callback);
|
|
159
157
|
} catch (error) {
|
|
160
158
|
this.log('error', '事务执行失败', error);
|
|
161
159
|
// 返回null作为默认值,保持返回值类型一致
|
|
@@ -257,7 +255,7 @@ DB.prototype.addTable = async function (table, field, type = 'int', auto = true,
|
|
|
257
255
|
sql += ' ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;';
|
|
258
256
|
|
|
259
257
|
// 执行SQL并设置表名
|
|
260
|
-
const result = await this.exec(sql, timeout);
|
|
258
|
+
const result = await this.exec(sql, [], timeout);
|
|
261
259
|
// 设置实例的表名属性,以便后续操作使用
|
|
262
260
|
this.table = table;
|
|
263
261
|
return result;
|
|
@@ -277,7 +275,7 @@ DB.prototype.dropTable = function (table, timeout = 15000) {
|
|
|
277
275
|
if (!table || typeof table !== 'string') {
|
|
278
276
|
throw new TypeError('table must be a valid string');
|
|
279
277
|
}
|
|
280
|
-
return this.exec('DROP TABLE IF EXISTS \`' + table + '\`;', timeout);
|
|
278
|
+
return this.exec('DROP TABLE IF EXISTS \`' + table + '\`;', [], timeout);
|
|
281
279
|
};
|
|
282
280
|
|
|
283
281
|
/**
|
|
@@ -291,7 +289,7 @@ DB.prototype.renameTable = function (table, new_table, timeout = 15000) {
|
|
|
291
289
|
if (!table || !new_table) {
|
|
292
290
|
throw new TypeError('table and new_table must be specified');
|
|
293
291
|
}
|
|
294
|
-
return this.exec('RENAME TABLE \`' + table + '\` TO \`' + new_table + '\`;', timeout);
|
|
292
|
+
return this.exec('RENAME TABLE \`' + table + '\` TO \`' + new_table + '\`;', [], timeout);
|
|
295
293
|
};
|
|
296
294
|
|
|
297
295
|
/**
|
|
@@ -341,7 +339,7 @@ DB.prototype.addField = async function (field, type, value = '', not_null = true
|
|
|
341
339
|
|
|
342
340
|
// 使用ADD COLUMN而不是CHANGE COLUMN
|
|
343
341
|
const sql = `ALTER TABLE \`${this.table}\` ADD COLUMN ${fieldDef};`;
|
|
344
|
-
const result = await this.exec(sql, timeout);
|
|
342
|
+
const result = await this.exec(sql, [], timeout);
|
|
345
343
|
return result;
|
|
346
344
|
} catch (err) {
|
|
347
345
|
this.log('error', '添加字段失败', err);
|
|
@@ -386,7 +384,7 @@ DB.prototype.setField = async function (field, type, value = '', not_null = true
|
|
|
386
384
|
sql += ', ADD PRIMARY KEY (\`' + targetName + '\`)';
|
|
387
385
|
}
|
|
388
386
|
sql += ';';
|
|
389
|
-
const result = await this.exec(sql, timeout);
|
|
387
|
+
const result = await this.exec(sql, [], timeout);
|
|
390
388
|
return result;
|
|
391
389
|
} catch (err) {
|
|
392
390
|
this.log('error', '修改字段失败', err);
|
|
@@ -406,7 +404,7 @@ DB.prototype.editField = function (table, field, type, timeout = 15000) {
|
|
|
406
404
|
if (!table || !field || !type) {
|
|
407
405
|
throw new TypeError('table, field, and type must be specified');
|
|
408
406
|
}
|
|
409
|
-
return this.exec('ALTER TABLE \`' + table + '\` MODIFY COLUMN \`' + field + '\` ' + type + ';', timeout);
|
|
407
|
+
return this.exec('ALTER TABLE \`' + table + '\` MODIFY COLUMN \`' + field + '\` ' + type + ';', [], timeout);
|
|
410
408
|
};
|
|
411
409
|
|
|
412
410
|
/**
|
|
@@ -420,7 +418,7 @@ DB.prototype.delField = function (table, field, timeout = 15000) {
|
|
|
420
418
|
if (!table || !field) {
|
|
421
419
|
throw new TypeError('table and field must be specified');
|
|
422
420
|
}
|
|
423
|
-
return this.exec('ALTER TABLE \`' + table + '\` DROP COLUMN \`' + field + '\`;', timeout);
|
|
421
|
+
return this.exec('ALTER TABLE \`' + table + '\` DROP COLUMN \`' + field + '\`;', [], timeout);
|
|
424
422
|
};
|
|
425
423
|
|
|
426
424
|
/**
|
|
@@ -436,7 +434,7 @@ DB.prototype.renameField = function (table, field, new_field, type, timeout = 15
|
|
|
436
434
|
if (!table || !field || !new_field) {
|
|
437
435
|
throw new TypeError('table, field, and new_field must be specified');
|
|
438
436
|
}
|
|
439
|
-
return this.exec('ALTER TABLE \`' + table + '\` CHANGE \`' + field + '\` \`' + new_field + '\` ' + type + ';', timeout);
|
|
437
|
+
return this.exec('ALTER TABLE \`' + table + '\` CHANGE \`' + field + '\` \`' + new_field + '\` ' + type + ';', [], timeout);
|
|
440
438
|
};
|
|
441
439
|
|
|
442
440
|
/**
|
|
@@ -529,7 +527,7 @@ DB.prototype.emptyTable = function (table, timeout = 15000) {
|
|
|
529
527
|
if (!table || typeof table !== 'string') {
|
|
530
528
|
throw new TypeError('table must be a valid string');
|
|
531
529
|
}
|
|
532
|
-
return this.exec('TRUNCATE TABLE \`' + table + '\`;', timeout);
|
|
530
|
+
return this.exec('TRUNCATE TABLE \`' + table + '\`;', [], timeout);
|
|
533
531
|
};
|
|
534
532
|
|
|
535
533
|
/**
|
|
@@ -582,7 +580,7 @@ DB.prototype.backupTable = function (table, backup, timeout = 60000) {
|
|
|
582
580
|
if (!table || !backup) {
|
|
583
581
|
throw new TypeError('table and backup must be specified');
|
|
584
582
|
}
|
|
585
|
-
return this.exec('CREATE TABLE \`' + backup + '\` LIKE \`' + table + '\`; INSERT INTO \`' + backup + '\` SELECT * FROM \`' + table + '\`;', timeout);
|
|
583
|
+
return this.exec('CREATE TABLE \`' + backup + '\` LIKE \`' + table + '\`; INSERT INTO \`' + backup + '\` SELECT * FROM \`' + table + '\`;', [], timeout);
|
|
586
584
|
};
|
|
587
585
|
|
|
588
586
|
|
|
@@ -591,7 +589,7 @@ DB.prototype.backupTable = function (table, backup, timeout = 60000) {
|
|
|
591
589
|
* @param {string} table 表名
|
|
592
590
|
* @param {object} model 表模型,键值对,根据值类型创建字段类型,根据键名创建字段名
|
|
593
591
|
* @param {string} key 主键
|
|
594
|
-
* @param timeout
|
|
592
|
+
* @param {number} timeout 超时时间(毫秒)
|
|
595
593
|
* @returns {Promise | number} 操作结果
|
|
596
594
|
*/
|
|
597
595
|
DB.prototype.createTable = function (table, model, key = 'id', timeout = 15000) {
|
package/package.json
CHANGED
package/sql.js
CHANGED
|
@@ -750,19 +750,10 @@ Sql.prototype.get = async function (query, sort, view, like, timeout = 20000) {
|
|
|
750
750
|
}
|
|
751
751
|
|
|
752
752
|
try {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
const sql = this.toGetSql(query, sort, view, like);
|
|
758
|
-
this.sql = sql;
|
|
759
|
-
const list = await this.run(sql);
|
|
760
|
-
return list;
|
|
761
|
-
})(),
|
|
762
|
-
new Promise((resolve, reject) => {
|
|
763
|
-
setTimeout(() => reject(new Error('查询操作超时')), timeout);
|
|
764
|
-
})
|
|
765
|
-
]);
|
|
753
|
+
const sql = this.toGetSql(query, sort, view, like);
|
|
754
|
+
this.sql = sql;
|
|
755
|
+
const list = await this.run(sql);
|
|
756
|
+
return list;
|
|
766
757
|
} catch (err) {
|
|
767
758
|
this.error = err.message;
|
|
768
759
|
this.log('error', '查询数据失败', err);
|
|
@@ -825,23 +816,12 @@ Sql.prototype.count = async function (query, like, timeout = 20000) {
|
|
|
825
816
|
}
|
|
826
817
|
|
|
827
818
|
try {
|
|
828
|
-
|
|
829
|
-
const
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
return
|
|
834
|
-
(async () => {
|
|
835
|
-
// 正确生成count SQL
|
|
836
|
-
const where = typeof query === 'string' ? query : await this.toWhere(query, like);
|
|
837
|
-
const sql = 'SELECT COUNT(*) as num FROM `' + this.table + '`' + (where ? ' WHERE ' + where : '');
|
|
838
|
-
this.sql = sql;
|
|
839
|
-
const list = await this.run(sql);
|
|
840
|
-
const total = list && list[0] && list[0].num ? parseInt(list[0].num) : 0;
|
|
841
|
-
return total;
|
|
842
|
-
})(),
|
|
843
|
-
timeout_promise
|
|
844
|
-
]);
|
|
819
|
+
const where = typeof query === 'string' ? query : await this.toWhere(query, like);
|
|
820
|
+
const sql = 'SELECT COUNT(*) as num FROM `' + this.table + '`' + (where ? ' WHERE ' + where : '');
|
|
821
|
+
this.sql = sql;
|
|
822
|
+
const list = await this.run(sql);
|
|
823
|
+
const total = list && list[0] && list[0].num ? parseInt(list[0].num) : 0;
|
|
824
|
+
return total;
|
|
845
825
|
} catch (err) {
|
|
846
826
|
this.error = err.message;
|
|
847
827
|
this.log('error', '统计数据失败', err);
|
|
@@ -865,57 +845,40 @@ Sql.prototype.getCount = async function (query, like, timeout = 30000) {
|
|
|
865
845
|
* 添加多条数据
|
|
866
846
|
* @param {Array} list 对象数组
|
|
867
847
|
* @param {boolean} lock 是否锁定
|
|
868
|
-
* @param {number}
|
|
848
|
+
* @param {number} batch_size 每批处理数量,默认100
|
|
869
849
|
* @param {number} timeout 超时时间(毫秒),默认60000
|
|
870
850
|
* @returns {Promise<object>} 执行结果
|
|
871
851
|
*/
|
|
872
|
-
Sql.prototype.addList = async function (list,
|
|
852
|
+
Sql.prototype.addList = async function (list, batch_size = 100, timeout = 60000) {
|
|
873
853
|
if (!this.table || !Array.isArray(list) || list.length === 0) {
|
|
874
854
|
throw new Error('表名或数据列表未设置');
|
|
875
855
|
}
|
|
876
856
|
try {
|
|
877
|
-
//
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
857
|
+
// 如果数据量较小,
|
|
858
|
+
if (list.length <= batch_size) {
|
|
859
|
+
// 使用批量插入语法,不使用事务包装
|
|
860
|
+
this.sql = this.toBatchAddSql(list);
|
|
861
|
+
return await this.exec(this.sql, [], timeout);
|
|
862
|
+
}
|
|
881
863
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
if (list.length <= batchSize) {
|
|
886
|
-
// 使用批量插入语法,不使用事务包装
|
|
887
|
-
this.sql = this.toBatchAddSql(list);
|
|
888
|
-
return await this.exec(this.sql);
|
|
889
|
-
}
|
|
864
|
+
// 分批处理大数据量
|
|
865
|
+
const batches = Math.ceil(list.length / batch_size);
|
|
866
|
+
this.log('info', `开始分批添加数据,共${batches}批,每批${batch_size}条`);
|
|
890
867
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
let final_res = null;
|
|
897
|
-
for (let i = 0; i < batches; i++) {
|
|
898
|
-
const batch = list.slice(i * batchSize, (i + 1) * batchSize);
|
|
899
|
-
this.log('debug', `处理第${i + 1}/${batches}批数据,${batch.length}条`);
|
|
900
|
-
|
|
901
|
-
// 生成批量插入SQL
|
|
902
|
-
const batch_sql = this.toBatchAddSql(batch);
|
|
903
|
-
this.sql = batch_sql;
|
|
904
|
-
|
|
905
|
-
// 为每批操作添加超时控制
|
|
906
|
-
final_res = await Promise.race([
|
|
907
|
-
this.exec(batch_sql),
|
|
908
|
-
new Promise((_, reject) => {
|
|
909
|
-
setTimeout(() => reject(new Error(`第${i + 1}批数据处理超时`)), timeout / batches);
|
|
910
|
-
})
|
|
911
|
-
]);
|
|
912
|
-
}
|
|
868
|
+
// 分批执行,每批一个单独的批量插入语句
|
|
869
|
+
let final_res = null;
|
|
870
|
+
for (let i = 0; i < batches; i++) {
|
|
871
|
+
const batch = list.slice(i * batch_size, (i + 1) * batch_size);
|
|
872
|
+
this.log('debug', `处理第${i + 1}/${batches}批数据,${batch.length}条`);
|
|
913
873
|
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
874
|
+
// 生成批量插入SQL
|
|
875
|
+
const batch_sql = this.toBatchAddSql(batch);
|
|
876
|
+
this.sql = batch_sql;
|
|
877
|
+
final_res = await this.exec(batch_sql);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
this.log('info', `批量添加数据完成,共${list.length}条`);
|
|
881
|
+
return final_res;
|
|
919
882
|
} catch (error) {
|
|
920
883
|
this.log('error', '批量添加数据失败', error);
|
|
921
884
|
}
|
|
@@ -970,78 +933,62 @@ Sql.prototype._buildValueList = function (list, keys) {
|
|
|
970
933
|
* 删除多条数据
|
|
971
934
|
* @param {Array} list 对象数组
|
|
972
935
|
* @param {boolean} like 是否使用like匹配, 为空使用默认方式
|
|
973
|
-
* @param {number}
|
|
936
|
+
* @param {number} batch_size 每批处理数量,默认100
|
|
974
937
|
* @param {number} timeout 超时时间(毫秒),默认60000
|
|
975
938
|
* @returns {Promise<object>} 执行结果
|
|
976
939
|
*/
|
|
977
|
-
Sql.prototype.delList = async function (list, like,
|
|
940
|
+
Sql.prototype.delList = async function (list, like, batch_size = 100, timeout = 60000) {
|
|
978
941
|
if (!this.table || !Array.isArray(list) || list.length === 0) {
|
|
979
942
|
throw new Error('表名或数据列表未设置');
|
|
980
943
|
}
|
|
981
944
|
try {
|
|
982
|
-
//
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
945
|
+
// 如果数据量较小,直接处理
|
|
946
|
+
if (list.length <= batch_size) {
|
|
947
|
+
let sql = '';
|
|
948
|
+
for (const item of list) {
|
|
949
|
+
sql += this.toDelSql(item.query, like);
|
|
950
|
+
}
|
|
951
|
+
this.sql = sql;
|
|
952
|
+
return await this.exec(sql);
|
|
953
|
+
}
|
|
986
954
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
if (list.length <= batchSize) {
|
|
991
|
-
let sql = '';
|
|
992
|
-
for (const item of list) {
|
|
993
|
-
sql += this.toDelSql(item.query, like);
|
|
994
|
-
}
|
|
995
|
-
this.sql = sql;
|
|
996
|
-
return await this.exec(sql);
|
|
997
|
-
}
|
|
955
|
+
// 分批处理大数据量
|
|
956
|
+
const batches = Math.ceil(list.length / batch_size);
|
|
957
|
+
this.log('info', `开始分批删除数据,共${batches}批,每批${batch_size}条`);
|
|
998
958
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
let final_res = null;
|
|
1005
|
-
try {
|
|
1006
|
-
// 开始事务
|
|
1007
|
-
await this.exec('BEGIN;', 15000);
|
|
1008
|
-
|
|
1009
|
-
// 分批处理
|
|
1010
|
-
for (let i = 0; i < batches; i++) {
|
|
1011
|
-
const batch = list.slice(i * batchSize, (i + 1) * batchSize);
|
|
1012
|
-
this.log('debug', `处理第${i + 1}/${batches}批数据,${batch.length}条`);
|
|
1013
|
-
|
|
1014
|
-
let batch_sql = '';
|
|
1015
|
-
for (const item of batch) {
|
|
1016
|
-
batch_sql += this.toDelSql(item.query, like);
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
// 为每批操作添加超时控制
|
|
1020
|
-
final_res = await Promise.race([
|
|
1021
|
-
this.exec(batch_sql),
|
|
1022
|
-
new Promise((_, reject) => {
|
|
1023
|
-
setTimeout(() => reject(new Error(`第${i + 1}批数据删除超时`)), timeout / batches);
|
|
1024
|
-
})
|
|
1025
|
-
]);
|
|
1026
|
-
}
|
|
959
|
+
// 使用事务包装整个操作以保证原子性
|
|
960
|
+
let final_res = null;
|
|
961
|
+
try {
|
|
962
|
+
// 开始事务
|
|
963
|
+
await this.exec('BEGIN;');
|
|
1027
964
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
this.log('error', '批量删除数据失败,事务回滚也失败', rollbackError);
|
|
1037
|
-
}
|
|
965
|
+
// 分批处理exec删除语句
|
|
966
|
+
for (let i = 0; i < batches; i++) {
|
|
967
|
+
const batch = list.slice(i * batch_size, (i + 1) * batch_size);
|
|
968
|
+
this.log('debug', `处理第${i + 1}/${batches}批数据,${batch.length}条`);
|
|
969
|
+
|
|
970
|
+
let batch_sql = '';
|
|
971
|
+
for (const item of batch) {
|
|
972
|
+
batch_sql += this.toDelSql(item.query, like);
|
|
1038
973
|
}
|
|
974
|
+
final_res = await this.exec(batch_sql);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// 提交事务
|
|
978
|
+
await this.exec('COMMIT;');
|
|
979
|
+
} catch (error) {
|
|
980
|
+
// 发生错误时回滚事务
|
|
981
|
+
try {
|
|
982
|
+
await this.exec('ROLLBACK;', [], timeout);
|
|
983
|
+
this.log('error', '批量删除数据失败,事务已回滚', error);
|
|
984
|
+
} catch (rollbackError) {
|
|
985
|
+
this.log('error', '批量删除数据失败,事务回滚也失败', rollbackError);
|
|
986
|
+
}
|
|
987
|
+
throw error; // 重新抛出错误
|
|
988
|
+
}
|
|
1039
989
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
})(),
|
|
1043
|
-
timeoutPromise
|
|
1044
|
-
]);
|
|
990
|
+
this.log('info', `批量删除数据完成,共${list.length}条`);
|
|
991
|
+
return final_res;
|
|
1045
992
|
} catch (err) {
|
|
1046
993
|
this.error = err.message;
|
|
1047
994
|
this.log('error', '批量删除数据失败', err);
|
|
@@ -1053,50 +1000,52 @@ Sql.prototype.delList = async function (list, like, batchSize = 100, timeout = 6
|
|
|
1053
1000
|
* 修改多条数据
|
|
1054
1001
|
* @param {Array} list 对象数组
|
|
1055
1002
|
* @param {boolean} like 是否使用like匹配, 为空使用默认方式
|
|
1056
|
-
* @param {number}
|
|
1003
|
+
* @param {number} batch_size 每批处理数量,默认100
|
|
1057
1004
|
* @param {number} timeout 超时时间(毫秒),默认60000
|
|
1058
1005
|
* @returns {Promise<object>} 执行结果
|
|
1059
1006
|
*/
|
|
1060
|
-
Sql.prototype.setList = async function (list, like = false,
|
|
1007
|
+
Sql.prototype.setList = async function (list, like = false, batch_size = 100, timeout = 60000) {
|
|
1061
1008
|
if (!this.table || !Array.isArray(list) || list.length === 0) {
|
|
1062
1009
|
throw new Error('表名或数据列表未设置');
|
|
1063
1010
|
}
|
|
1064
1011
|
try {
|
|
1065
|
-
//
|
|
1066
|
-
const
|
|
1067
|
-
|
|
1068
|
-
});
|
|
1012
|
+
// 分批处理大数据量
|
|
1013
|
+
const batches = Math.ceil(list.length / batch_size);
|
|
1014
|
+
this.log('info', `开始分批修改数据,共${batches}批,每批${batch_size}条`);
|
|
1069
1015
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1016
|
+
let final_res = null;
|
|
1017
|
+
|
|
1018
|
+
// 使用事务包装整个操作以保证原子性
|
|
1019
|
+
try {
|
|
1020
|
+
// 开始事务
|
|
1021
|
+
await this.exec('BEGIN;');
|
|
1022
|
+
|
|
1023
|
+
// 逐条处理记录,保持简单可靠
|
|
1024
|
+
for (let i = 0; i < list.length; i++) {
|
|
1025
|
+
const item = list[i];
|
|
1026
|
+
this.log('debug', `处理第${i + 1}/${list.length}条记录`);
|
|
1027
|
+
|
|
1028
|
+
// 生成单个更新SQL
|
|
1029
|
+
const sql = this.toSetSql(item.query, item.item, like);
|
|
1030
|
+
this.sql = sql;
|
|
1031
|
+
|
|
1032
|
+
final_res = await this.exec(sql, [], timeout);
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// 提交事务
|
|
1036
|
+
await this.exec('COMMIT;');
|
|
1037
|
+
} catch (error) {
|
|
1038
|
+
// 发生错误时回滚事务
|
|
1039
|
+
try {
|
|
1040
|
+
await this.exec('ROLLBACK;', [], timeout);
|
|
1041
|
+
this.log('error', '批量修改数据失败,事务已回滚', error);
|
|
1042
|
+
} catch (rollbackError) {
|
|
1043
|
+
this.log('error', '批量修改数据失败,事务回滚也失败', rollbackError);
|
|
1044
|
+
}
|
|
1045
|
+
throw error; // 重新抛出错误
|
|
1046
|
+
}
|
|
1095
1047
|
|
|
1096
|
-
|
|
1097
|
-
})(),
|
|
1098
|
-
timeoutPromise
|
|
1099
|
-
]);
|
|
1048
|
+
return final_res;
|
|
1100
1049
|
} catch (error) {
|
|
1101
1050
|
this.error = error.message;
|
|
1102
1051
|
this.log('error', '批量修改数据失败', error);
|