@maiyunnet/kebab 4.1.0 → 5.0.1
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.d.ts +7 -2
- package/index.js +1 -1
- package/lib/db/conn.d.ts +91 -0
- package/lib/db/conn.js +328 -0
- package/lib/db/pool.d.ts +61 -0
- package/lib/db/pool.js +281 -0
- package/lib/db/tran.d.ts +33 -0
- package/lib/db/tran.js +122 -0
- package/lib/db.d.ts +35 -169
- package/lib/db.js +21 -582
- package/lib/scan.js +2 -2
- package/lib/sql.d.ts +24 -25
- package/lib/sql.js +230 -132
- package/lib/time.d.ts +1 -1
- package/lib/time.js +1 -1
- package/lib/turnstile.js +1 -1
- package/lib/vector.d.ts +9 -4
- package/lib/vector.js +46 -27
- package/package.json +6 -5
- package/sys/cmd.js +29 -6
- package/sys/mod.d.ts +8 -26
- package/sys/mod.js +110 -261
- package/www/example/ctr/test.js +119 -112
- package/www/example/data/test.zip +0 -0
- package/www/example/mod/test.js +22 -0
package/lib/db.js
CHANGED
|
@@ -1,594 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Project: Kebab, User: JianSuoQiYue
|
|
3
3
|
* Date: 2019-4-15 13:40
|
|
4
|
-
* Last: 2020-4-13 15:34:45, 2022-09-12 13:10:34, 2023-5-24 18:29:38, 2024-7-11 14:37:54, 2024-8-25 00:32:53, 2024-9-22 17:30:47, 2025-8-3 20:24:03
|
|
4
|
+
* Last: 2020-4-13 15:34:45, 2022-09-12 13:10:34, 2023-5-24 18:29:38, 2024-7-11 14:37:54, 2024-8-25 00:32:53, 2024-9-22 17:30:47, 2025-8-3 20:24:03, 2025-11-8 19:13:03
|
|
5
5
|
*/
|
|
6
|
-
// --- Pool 是使用时必须要一个用户创建一份的,Connection 是池子里获取的 ---
|
|
7
|
-
// --- 第三方 ---
|
|
8
|
-
import * as mysql2 from 'mysql2/promise';
|
|
9
|
-
import * as lTime from '#kebab/lib/time.js';
|
|
10
|
-
import * as lSql from '#kebab/lib/sql.js';
|
|
11
|
-
import * as lCore from '#kebab/lib/core.js';
|
|
12
6
|
import * as sCtr from '#kebab/sys/ctr.js';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (connection.isLost()) {
|
|
23
|
-
// --- 连接已经丢失,移除 ---
|
|
24
|
-
await connection.end();
|
|
25
|
-
connections.splice(i, 1);
|
|
26
|
-
--i;
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
if (connection.isUsing()) {
|
|
30
|
-
// --- 连接正在被使用,看看是否空闲了超过 30 秒,超过则不是正常状态 ---
|
|
31
|
-
if (connection.getLast() <= now - 30) {
|
|
32
|
-
// --- 30 秒之前开始的 ---
|
|
33
|
-
const ls = connection.getLastSql();
|
|
34
|
-
const newarr = ls.map(item => {
|
|
35
|
-
if (!item.values) {
|
|
36
|
-
return item.sql;
|
|
37
|
-
}
|
|
38
|
-
return lSql.format(item.sql, item.values);
|
|
39
|
-
});
|
|
40
|
-
const msg = `[DB][checkConnection] There is a transactional connection[${i}] that is not closed, last sql: ${newarr.join(', ')}.`;
|
|
41
|
-
lCore.display(msg);
|
|
42
|
-
lCore.log({}, msg, '-error');
|
|
43
|
-
await connection.rollback();
|
|
44
|
-
}
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
if (connection.getLast() <= now - 30) {
|
|
48
|
-
// --- 超 30 秒未被使用,则关闭 ---
|
|
49
|
-
await connection.end();
|
|
50
|
-
connections.splice(i, 1);
|
|
51
|
-
--i;
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
// --- 30 秒内使用过,看看连接是否正常 ---
|
|
55
|
-
if (await connection.isAvailable(false)) {
|
|
56
|
-
// --- 正常 ---
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
// --- 连接有问题,直接关闭 ---
|
|
60
|
-
await connection.end();
|
|
61
|
-
connections.splice(i, 1);
|
|
62
|
-
--i;
|
|
63
|
-
}
|
|
64
|
-
setTimeout(function () {
|
|
65
|
-
checkConnection().catch(e => { lCore.display('[DB][checkConnection]', e); });
|
|
66
|
-
}, 10_000);
|
|
67
|
-
}
|
|
68
|
-
setTimeout(function () {
|
|
69
|
-
checkConnection().catch(e => { lCore.display('[DB][checkConnection]', e); });
|
|
70
|
-
}, 10_000);
|
|
71
|
-
/** --- 数据库连接池对象 --- */
|
|
72
|
-
export class Pool {
|
|
73
|
-
constructor(etc) {
|
|
74
|
-
/** --- SQL 执行次数 --- */
|
|
75
|
-
this._queries = 0;
|
|
76
|
-
this._etc = etc;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* --- 执行一条 SQL,无视顺序和相同连接,随用随取 ---
|
|
80
|
-
* @param sql 执行的 SQL 字符串
|
|
81
|
-
* @param values 要替换的 data 数据
|
|
82
|
-
* @returns error.errno = -500 表示系统错误
|
|
83
|
-
*/
|
|
84
|
-
async query(sql, values) {
|
|
85
|
-
++this._queries;
|
|
86
|
-
// --- 获取并自动 using ---
|
|
87
|
-
const conn = await this._getConnection();
|
|
88
|
-
if (!conn) {
|
|
89
|
-
return {
|
|
90
|
-
'rows': null,
|
|
91
|
-
'fields': [],
|
|
92
|
-
'error': {
|
|
93
|
-
'message': 'false',
|
|
94
|
-
'errno': 0,
|
|
95
|
-
},
|
|
96
|
-
'result': -500,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
// --- 执行一次后自动解除 using ---
|
|
100
|
-
return conn.query(sql, values);
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* --- 执行一条 SQL 并获得影响行数对象 packet,连接失败抛出错误 ---
|
|
104
|
-
* @param sql 执行的 SQL 字符串
|
|
105
|
-
* @param values 要替换的 data 数据
|
|
106
|
-
*/
|
|
107
|
-
async execute(sql, values) {
|
|
108
|
-
++this._queries;
|
|
109
|
-
const conn = await this._getConnection();
|
|
110
|
-
if (!conn) {
|
|
111
|
-
return {
|
|
112
|
-
'packet': null,
|
|
113
|
-
'fields': [],
|
|
114
|
-
'error': {
|
|
115
|
-
'message': 'null',
|
|
116
|
-
'errno': 0
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
return conn.execute(sql, values);
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* --- 开启事务,返回事务对象并锁定连接,别人任何人不可用,有 ctr 的话必传 this,独立执行时可传 null ---
|
|
124
|
-
*/
|
|
125
|
-
async beginTransaction(ctr) {
|
|
126
|
-
const conn = await this._getConnection();
|
|
127
|
-
if (!conn) {
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
if (!await conn.beginTransaction()) {
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
return new Transaction(ctr, conn);
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* --- 获取一个连接,自动变为 using 状态,;连接失败会返回 null ---
|
|
137
|
-
*/
|
|
138
|
-
async _getConnection() {
|
|
139
|
-
let conn = null;
|
|
140
|
-
for (const connection of connections) {
|
|
141
|
-
const etc = connection.getEtc();
|
|
142
|
-
if ((etc.host !== this._etc.host) ||
|
|
143
|
-
(etc.port !== this._etc.port) ||
|
|
144
|
-
(etc.name !== this._etc.name) ||
|
|
145
|
-
(etc.user !== this._etc.user)) {
|
|
146
|
-
// --- 配置项连接项不匹配 ---
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
if (!connection.using()) {
|
|
150
|
-
// --- 正在被使用,或者已经 lost ---
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
// --- 匹配且可用 ---
|
|
154
|
-
conn = connection;
|
|
155
|
-
break;
|
|
156
|
-
}
|
|
157
|
-
if (!conn) {
|
|
158
|
-
// --- 没有找到合适的连接,创建一个 ---
|
|
159
|
-
for (let i = 0; i < 3; ++i) {
|
|
160
|
-
try {
|
|
161
|
-
const link = await mysql2.createConnection({
|
|
162
|
-
'host': this._etc.host,
|
|
163
|
-
'port': this._etc.port,
|
|
164
|
-
'charset': this._etc.charset,
|
|
165
|
-
'database': this._etc.name,
|
|
166
|
-
'user': this._etc.user,
|
|
167
|
-
'password': this._etc.pwd,
|
|
168
|
-
'connectTimeout': 3_000,
|
|
169
|
-
});
|
|
170
|
-
const c = new Connection(this._etc, link);
|
|
171
|
-
c.using();
|
|
172
|
-
link.on('error', function (err) {
|
|
173
|
-
c.setLost();
|
|
174
|
-
if (err.code !== 'PROTOCOL_CONNECTION_LOST') {
|
|
175
|
-
lCore.debug('[DB][_getConnection][error]', err);
|
|
176
|
-
lCore.log({}, '[DB][_getConnection][error] ' + err.message, '-error');
|
|
177
|
-
}
|
|
178
|
-
}).on('end', () => {
|
|
179
|
-
// lCore.debug('[DB][_getConnection] connection end.');
|
|
180
|
-
c.setLost();
|
|
181
|
-
}).on('close', () => {
|
|
182
|
-
c.setLost();
|
|
183
|
-
});
|
|
184
|
-
conn = c;
|
|
185
|
-
connections.push(conn);
|
|
186
|
-
break;
|
|
187
|
-
}
|
|
188
|
-
catch (err) {
|
|
189
|
-
if (err.message === 'ETIMEOUT' || err.message === 'EHOSTUNREACH') {
|
|
190
|
-
lCore.debug('[DB][_getConnection][TIMEOUT|HOSTUNREACH]', err);
|
|
191
|
-
await lCore.sleep(300);
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
const msg = `[DB][_getConnection] ${err.message}(${this._etc.host}:${this._etc.port})`;
|
|
195
|
-
lCore.debug(msg);
|
|
196
|
-
lCore.log({}, msg, '-error');
|
|
197
|
-
break;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return conn;
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* --- 获取 SQL 执行次数 ---
|
|
205
|
-
*/
|
|
206
|
-
getQueries() {
|
|
207
|
-
return this._queries;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
/** --- 事务连接对象,commit 和 rollback 后将无法使用 --- */
|
|
211
|
-
export class Transaction {
|
|
212
|
-
constructor(ctr, conn, opts = {}) {
|
|
213
|
-
/** --- SQL 执行次数 --- */
|
|
214
|
-
this._queries = 0;
|
|
215
|
-
// --- 事务时长监听 timer ---
|
|
216
|
-
this._timer = {
|
|
217
|
-
'warning': undefined,
|
|
218
|
-
'danger': undefined
|
|
219
|
-
};
|
|
220
|
-
// --- 进来的连接对象直接是事务独占模式 ---
|
|
221
|
-
this._ctr = ctr;
|
|
222
|
-
if (ctr) {
|
|
223
|
-
++ctr.getPrototype('_waitInfo').transaction;
|
|
224
|
-
}
|
|
225
|
-
this._conn = conn;
|
|
226
|
-
// --- 事务时长监听 ---
|
|
227
|
-
const warning = opts.warning ?? 1_500;
|
|
228
|
-
this._timer.warning = setTimeout(() => {
|
|
229
|
-
this._timer.warning = undefined;
|
|
230
|
-
lCore.display('[WARNING][DB][Transaction] time too long, ms: ' + warning + ' ' + (this._ctr?.getPrototype('_config').const.path ?? 'no ctr'));
|
|
231
|
-
}, warning);
|
|
232
|
-
const danger = opts.danger ?? 5_000;
|
|
233
|
-
this._timer.danger = setTimeout(() => {
|
|
234
|
-
this._timer.danger = undefined;
|
|
235
|
-
lCore.display('[DANGER][DB][Transaction] time too long, ms:', danger, this._ctr?.getPrototype('_config').const.path ?? 'no ctr');
|
|
236
|
-
}, danger);
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* --- 在事务连接中执行一条 SQL ---
|
|
240
|
-
* @param sql 执行的 SQL 字符串
|
|
241
|
-
* @param values 要替换的 data 数据
|
|
242
|
-
*/
|
|
243
|
-
async query(sql, values) {
|
|
244
|
-
if (!this._conn) {
|
|
245
|
-
// --- 当前连接已不可用 ---
|
|
246
|
-
lCore.display('[DB][Transaction][query] has been closed ' + (this._ctr?.getPrototype('_config').const.path ?? 'no ctr') + ': ' + sql);
|
|
247
|
-
lCore.log({}, '[DB][Transaction][query] has been closed ' + (this._ctr?.getPrototype('_config').const.path ?? 'no ctr') + ': ' + sql, '-error');
|
|
248
|
-
return {
|
|
249
|
-
'rows': null,
|
|
250
|
-
'fields': [],
|
|
251
|
-
'error': {
|
|
252
|
-
'message': 'false',
|
|
253
|
-
'errno': 0
|
|
254
|
-
},
|
|
255
|
-
'result': -500,
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
++this._queries;
|
|
259
|
-
return this._conn.query(sql, values);
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* --- 执行一条 SQL 并获得影响行数对象 packet,连接失败抛出错误 ---
|
|
263
|
-
* @param sql 执行的 SQL 字符串
|
|
264
|
-
* @param values 要替换的 data 数据
|
|
265
|
-
*/
|
|
266
|
-
async execute(sql, values) {
|
|
267
|
-
if (!this._conn) {
|
|
268
|
-
// --- 当前连接已不可用 ---
|
|
269
|
-
lCore.display('[DB][Transaction][execute] has been closed ' + (this._ctr?.getPrototype('_config').const.path ?? 'no ctr') + ': ' + sql);
|
|
270
|
-
lCore.log({}, '(db.Transaction.execute) has been closed ' + (this._ctr?.getPrototype('_config').const.path ?? 'no ctr') + ': ' + sql, '-error');
|
|
271
|
-
return {
|
|
272
|
-
'packet': null,
|
|
273
|
-
'fields': [],
|
|
274
|
-
'error': {
|
|
275
|
-
'message': 'null',
|
|
276
|
-
'errno': 0
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
++this._queries;
|
|
281
|
-
return this._conn.execute(sql, values);
|
|
282
|
-
}
|
|
283
|
-
async commit() {
|
|
284
|
-
if (!this._conn) {
|
|
285
|
-
// --- 当前连接已不可用 ---
|
|
286
|
-
lCore.display('[DB][Transaction][commit] has been closed ' + (this._ctr?.getPrototype('_config').const.path ?? 'no ctr'));
|
|
287
|
-
lCore.log({}, '[DB][Transaction][commit] has been closed ' + (this._ctr?.getPrototype('_config').const.path ?? 'no ctr'), '-error');
|
|
288
|
-
return false;
|
|
289
|
-
}
|
|
290
|
-
const r = await this._conn.commit();
|
|
291
|
-
if (!r) {
|
|
292
|
-
return false;
|
|
293
|
-
}
|
|
294
|
-
this._conn = null;
|
|
295
|
-
if (this._ctr) {
|
|
296
|
-
--this._ctr.getPrototype('_waitInfo').transaction;
|
|
297
|
-
}
|
|
298
|
-
clearTimeout(this._timer.warning);
|
|
299
|
-
this._timer.warning = undefined;
|
|
300
|
-
clearTimeout(this._timer.danger);
|
|
301
|
-
this._timer.danger = undefined;
|
|
302
|
-
return true;
|
|
303
|
-
}
|
|
304
|
-
async rollback() {
|
|
305
|
-
if (!this._conn) {
|
|
306
|
-
// --- 当前连接已不可用 ---
|
|
307
|
-
lCore.display('[DB][Transaction][rollback] has been closed: ' + (this._ctr?.getPrototype('_config').const.path ?? 'no ctr'));
|
|
308
|
-
lCore.log({}, '[DB][Transaction][rollback] has been closed: ' + (this._ctr?.getPrototype('_config').const.path ?? 'no ctr'), '-error');
|
|
309
|
-
return false;
|
|
310
|
-
}
|
|
311
|
-
const r = await this._conn.rollback();
|
|
312
|
-
if (!r) {
|
|
313
|
-
return false;
|
|
314
|
-
}
|
|
315
|
-
this._conn = null;
|
|
316
|
-
if (this._ctr) {
|
|
317
|
-
--this._ctr.getPrototype('_waitInfo').transaction;
|
|
318
|
-
}
|
|
319
|
-
clearTimeout(this._timer.warning);
|
|
320
|
-
this._timer.warning = undefined;
|
|
321
|
-
clearTimeout(this._timer.danger);
|
|
322
|
-
this._timer.danger = undefined;
|
|
323
|
-
return true;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
/** --- 数据库连接对象 --- */
|
|
327
|
-
export class Connection {
|
|
328
|
-
constructor(etc, link) {
|
|
329
|
-
/** --- 本连接最后一次使用时间 --- */
|
|
330
|
-
this._last = 0;
|
|
331
|
-
/** --- 最后两次执行的 sql 完整串 --- */
|
|
332
|
-
this._lastSql = [];
|
|
333
|
-
/** --- 当前连接是否正在被独占使用 --- */
|
|
334
|
-
this._using = false;
|
|
335
|
-
/** --- 当发生断开,则需从连接池移除连接 --- */
|
|
336
|
-
this._lost = false;
|
|
337
|
-
/** --- 当前正在处理事务 --- */
|
|
338
|
-
this._transaction = false;
|
|
339
|
-
this._etc = etc;
|
|
340
|
-
this._link = link;
|
|
341
|
-
this.refreshLast();
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* --- 获取连接 etc 信息 ---
|
|
345
|
-
*/
|
|
346
|
-
getEtc() {
|
|
347
|
-
return this._etc;
|
|
348
|
-
}
|
|
349
|
-
/**
|
|
350
|
-
* --- 获取最后一次获取连接的时间 ---
|
|
351
|
-
*/
|
|
352
|
-
getLast() {
|
|
353
|
-
return this._last;
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* --- 获取最后两次执行的 sql 字符串 ---
|
|
357
|
-
*/
|
|
358
|
-
getLastSql() {
|
|
359
|
-
return this._lastSql;
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* --- 将本条连接设置为不可用 ---
|
|
363
|
-
*/
|
|
364
|
-
setLost() {
|
|
365
|
-
this._lost = true;
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* --- 是否已经丢失 ---
|
|
369
|
-
*/
|
|
370
|
-
isLost() {
|
|
371
|
-
return this._lost;
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* --- 是否是开启事务状态 ---
|
|
375
|
-
*/
|
|
376
|
-
isTransaction() {
|
|
377
|
-
return this._transaction;
|
|
378
|
-
}
|
|
379
|
-
/**
|
|
380
|
-
* --- 获取当前状态是否正在被使用中 ---
|
|
381
|
-
*/
|
|
382
|
-
isUsing() {
|
|
383
|
-
return this._using;
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* --- 判断是否可用(丢失的也算不可用),返回 true 代表获取成功并自动刷新最后时间 ---
|
|
387
|
-
*/
|
|
388
|
-
using() {
|
|
389
|
-
if (this._lost || this._using) {
|
|
390
|
-
return false;
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
this.refreshLast();
|
|
394
|
-
this._using = true;
|
|
395
|
-
return true;
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* --- 取消占用 ---
|
|
400
|
-
*/
|
|
401
|
-
used() {
|
|
402
|
-
this._using = false;
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* --- 设定最后使用时间 ---
|
|
406
|
-
*/
|
|
407
|
-
refreshLast() {
|
|
408
|
-
this._last = lTime.stamp();
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* --- 通过执行一条语句判断当前连接是否可用 ---
|
|
412
|
-
* @param last 是否刷新最后使用时间(默认刷新)
|
|
413
|
-
*/
|
|
414
|
-
async isAvailable(last = true) {
|
|
415
|
-
if (last) {
|
|
416
|
-
this.refreshLast();
|
|
417
|
-
}
|
|
418
|
-
try {
|
|
419
|
-
await this._link.query('SELECT 1');
|
|
420
|
-
return true;
|
|
421
|
-
}
|
|
422
|
-
catch {
|
|
423
|
-
return false;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* --- 执行一条 SQL 并获得返回数据 ---
|
|
428
|
-
* @param sql 执行的 SQL 字符串
|
|
429
|
-
* @param values 要替换的 data 数据
|
|
430
|
-
*/
|
|
431
|
-
async query(sql, values) {
|
|
432
|
-
let res;
|
|
433
|
-
try {
|
|
434
|
-
this.refreshLast();
|
|
435
|
-
if (this._lastSql.length === 2) {
|
|
436
|
-
this._lastSql.splice(0, 1);
|
|
437
|
-
}
|
|
438
|
-
this._lastSql.push({
|
|
439
|
-
'sql': sql,
|
|
440
|
-
'values': values
|
|
441
|
-
});
|
|
442
|
-
const time = Date.now();
|
|
443
|
-
res = await this._link.query(sql, values);
|
|
444
|
-
if (Date.now() - time > 200) {
|
|
445
|
-
lCore.log({}, '[WARNING][DB][Connection][query] slow sql 200ms: ' + sql, '-warning');
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
catch (e) {
|
|
449
|
-
if (!this._transaction) {
|
|
450
|
-
this._using = false;
|
|
451
|
-
}
|
|
452
|
-
return {
|
|
453
|
-
'rows': null,
|
|
454
|
-
'fields': [],
|
|
455
|
-
'error': e,
|
|
456
|
-
'result': -500,
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
|
-
if (!this._transaction) {
|
|
460
|
-
this._using = false;
|
|
461
|
-
}
|
|
462
|
-
// --- 返回数据 ---
|
|
463
|
-
return {
|
|
464
|
-
'rows': res[0],
|
|
465
|
-
'fields': res[1],
|
|
466
|
-
'error': null,
|
|
467
|
-
'result': 1,
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* --- 执行一条 SQL 并获得影响行数对象 packet ---
|
|
472
|
-
* @param sql 执行的 SQL 字符串
|
|
473
|
-
* @param values 要替换的 data 数据
|
|
474
|
-
*/
|
|
475
|
-
async execute(sql, values) {
|
|
476
|
-
let res;
|
|
477
|
-
try {
|
|
478
|
-
this.refreshLast();
|
|
479
|
-
if (this._lastSql.length === 2) {
|
|
480
|
-
this._lastSql.splice(0, 1);
|
|
481
|
-
}
|
|
482
|
-
this._lastSql.push({
|
|
483
|
-
'sql': sql,
|
|
484
|
-
'values': values,
|
|
485
|
-
});
|
|
486
|
-
const time = Date.now();
|
|
487
|
-
res = await this._link.execute(sql, values);
|
|
488
|
-
if (Date.now() - time > 200) {
|
|
489
|
-
lCore.log({}, '[WARNING][DB][Connection][execute] slow sql 200ms: ' + sql, '-warning');
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
catch (e) {
|
|
493
|
-
if (!this._transaction) {
|
|
494
|
-
this._using = false;
|
|
495
|
-
}
|
|
496
|
-
// --- e.errno 可能为 1062 ---
|
|
497
|
-
return {
|
|
498
|
-
'packet': null,
|
|
499
|
-
'fields': [],
|
|
500
|
-
'error': e
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
if (!this._transaction) {
|
|
504
|
-
this._using = false;
|
|
505
|
-
}
|
|
506
|
-
return {
|
|
507
|
-
'packet': res[0],
|
|
508
|
-
'fields': res[1],
|
|
509
|
-
'error': null
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
/**
|
|
513
|
-
* --- 关闭连接,一般情况下不使用 ---
|
|
514
|
-
*/
|
|
515
|
-
async end() {
|
|
516
|
-
try {
|
|
517
|
-
await this._link.end();
|
|
518
|
-
return true;
|
|
519
|
-
}
|
|
520
|
-
catch {
|
|
521
|
-
return false;
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
// --- 事务,只能在独占连接中使用,pool 创建事务返回独占连接,commit 或 rollback 释放连接回池 ---
|
|
525
|
-
async beginTransaction() {
|
|
526
|
-
if (this._using) {
|
|
527
|
-
try {
|
|
528
|
-
this._transaction = true;
|
|
529
|
-
await this._link.beginTransaction();
|
|
530
|
-
return true;
|
|
531
|
-
}
|
|
532
|
-
catch {
|
|
533
|
-
return false;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
else {
|
|
537
|
-
return false;
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
async commit() {
|
|
541
|
-
try {
|
|
542
|
-
await this._link.commit();
|
|
543
|
-
this.refreshLast();
|
|
544
|
-
this._transaction = false;
|
|
545
|
-
this._using = false;
|
|
546
|
-
return true;
|
|
547
|
-
}
|
|
548
|
-
catch {
|
|
549
|
-
return false;
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
async rollback() {
|
|
553
|
-
try {
|
|
554
|
-
await this._link.rollback();
|
|
555
|
-
this.refreshLast();
|
|
556
|
-
this._transaction = false;
|
|
557
|
-
this._using = false;
|
|
558
|
-
return true;
|
|
559
|
-
}
|
|
560
|
-
catch {
|
|
561
|
-
return false;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
}
|
|
7
|
+
import { Connection } from './db/conn.js';
|
|
8
|
+
import { Pool } from './db/pool.js';
|
|
9
|
+
import { Transaction } from './db/tran.js';
|
|
10
|
+
/** --- 服务商定义 --- */
|
|
11
|
+
export var ESERVICE;
|
|
12
|
+
(function (ESERVICE) {
|
|
13
|
+
ESERVICE[ESERVICE["MYSQL"] = 0] = "MYSQL";
|
|
14
|
+
ESERVICE[ESERVICE["PGSQL"] = 1] = "PGSQL";
|
|
15
|
+
})(ESERVICE || (ESERVICE = {}));
|
|
565
16
|
/**
|
|
566
17
|
* --- 获取 Db Pool 对象 ---
|
|
567
18
|
* @param etc 配置信息可留空
|
|
568
19
|
*/
|
|
569
|
-
export function get(ctrEtc) {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
export function getConnectionList() {
|
|
577
|
-
const list = [];
|
|
578
|
-
for (let i = 0; i < connections.length; ++i) {
|
|
579
|
-
const connection = connections[i];
|
|
580
|
-
const etc = connection.getEtc();
|
|
581
|
-
list.push({
|
|
582
|
-
'id': i,
|
|
583
|
-
'last': connection.getLast(),
|
|
584
|
-
'host': etc.host,
|
|
585
|
-
'port': etc.port,
|
|
586
|
-
'name': etc.name,
|
|
587
|
-
'user': etc.user,
|
|
588
|
-
'lost': connection.isLost(),
|
|
589
|
-
'using': connection.isUsing(),
|
|
590
|
-
'transaction': connection.isTransaction()
|
|
20
|
+
export function get(ctrEtc, opt = {}) {
|
|
21
|
+
if (ctrEtc instanceof sCtr.Ctr) {
|
|
22
|
+
// --- 从 ctr 中读取连接信息 ---
|
|
23
|
+
const config = ctrEtc.getPrototype('_config');
|
|
24
|
+
const service = opt.service ? ESERVICE[opt.service] : config.db.default;
|
|
25
|
+
return new Pool(config.db[service].default, {
|
|
26
|
+
'service': service === 'MYSQL' ? ESERVICE.MYSQL : ESERVICE.PGSQL,
|
|
591
27
|
});
|
|
592
28
|
}
|
|
593
|
-
return
|
|
29
|
+
return new Pool(ctrEtc, {
|
|
30
|
+
'service': opt.service ?? ESERVICE.PGSQL,
|
|
31
|
+
});
|
|
594
32
|
}
|
|
33
|
+
export { Connection, Pool, Transaction };
|
package/lib/scan.js
CHANGED
|
@@ -241,7 +241,7 @@ export async function scanned(link, token, opt = {}) {
|
|
|
241
241
|
if (r.error) {
|
|
242
242
|
return false;
|
|
243
243
|
}
|
|
244
|
-
if (r.packet?.
|
|
244
|
+
if (r.packet?.affected) {
|
|
245
245
|
return true;
|
|
246
246
|
}
|
|
247
247
|
}
|
|
@@ -295,7 +295,7 @@ export async function setData(link, token, data, opt = {}) {
|
|
|
295
295
|
if (r.error) {
|
|
296
296
|
return false;
|
|
297
297
|
}
|
|
298
|
-
if (r.packet?.
|
|
298
|
+
if (r.packet?.affected) {
|
|
299
299
|
return true;
|
|
300
300
|
}
|
|
301
301
|
}
|