mysql78
Version:
nodejs koa78封装 上传类
481 lines • 20.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const mysql = tslib_1.__importStar(require("mysql2/promise"));
const koa78_upinfo_1 = tslib_1.__importDefault(require("koa78-upinfo"));
const tslog78_1 = tslib_1.__importDefault(require("tslog78"));
const md5_1 = tslib_1.__importDefault(require("md5"));
/**
* 如果不行就回退到2.4.0
*/
class Mysql78 {
constructor(config) {
var _a, _b, _c, _d, _e, _f;
this._statementCache = new Map();
this._pool = null;
this._host = '';
this.isLog = false;
this.isCount = false;
this.log = tslog78_1.default.Instance;
this.warnHandler = null;
// 设置重试次数和重试延迟
this.maxRetryAttempts = 3;
this.retryDelayMs = 1000; // 1秒延迟
if (!config)
return;
this._host = (_a = config.host) !== null && _a !== void 0 ? _a : '127.0.0.1';
const port = (_b = config.port) !== null && _b !== void 0 ? _b : 3306; // 端口
const max = (_c = config.max) !== null && _c !== void 0 ? _c : 10; // 最大线程数
const user = (_d = config.user) !== null && _d !== void 0 ? _d : 'root'; // mysql用户名
this.isLog = (_e = config.isLog) !== null && _e !== void 0 ? _e : false; // 是否打印日志(影响性能)
this.isCount = (_f = config.isCount) !== null && _f !== void 0 ? _f : false; // 是否统计效率(影响性能)
this._pool = mysql.createPool({
connectionLimit: max,
host: this._host,
port,
user,
password: config.password,
database: config.database,
dateStrings: true,
connectTimeout: 30 * 1000,
waitForConnections: true, // 等待连接池中的连接可用
});
}
// 延迟函数
delay(ms) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
return new Promise(resolve => setTimeout(resolve, ms));
});
}
// 获取连接,并在发生错误时重试
getConnectionWithRetry() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
var _a;
let attempts = 0;
while (attempts < this.maxRetryAttempts) {
try {
const connection = yield ((_a = this._pool) === null || _a === void 0 ? void 0 : _a.getConnection());
if (connection === undefined) {
return null; // Explicitly return null if connection is undefined
}
return connection;
}
catch (err) {
attempts++;
this.log.error(`Connection attempt ${attempts} failed:`, err);
if (attempts >= this.maxRetryAttempts) {
throw err;
}
yield this.delay(this.retryDelayMs);
}
}
return null;
});
}
// 重试函数的包装:用于 `doGet`、`doM`、`doT` 等方法
retryOperation(operation) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let attempts = 0;
while (attempts < this.maxRetryAttempts) {
try {
return yield operation();
}
catch (err) {
attempts++;
this.log.error(`Operation attempt ${attempts} failed:`, err);
if (attempts >= this.maxRetryAttempts) {
throw err;
}
yield this.delay(this.retryDelayMs);
}
}
throw new Error("Max retry attempts reached.");
});
}
/**
* 创建系统常用表
* Create system common table
*
* */
creatTb(up) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (!this._pool) {
return 'pool null';
}
const cmdtext1 = "CREATE TABLE IF NOT EXISTS `sys_warn` ( `uid` varchar(36) NOT NULL DEFAULT '', `kind` varchar(100) NOT NULL DEFAULT '', `apisys` varchar(100) NOT NULL DEFAULT '', `apiobj` varchar(100) NOT NULL DEFAULT '', `content` text NOT NULL, `upid` varchar(36) NOT NULL DEFAULT '', `upby` varchar(50) DEFAULT '', `uptime` datetime NOT NULL, `idpk` int(11) NOT NULL AUTO_INCREMENT, `id` varchar(36) NOT NULL, `remark` varchar(200) NOT NULL DEFAULT '', `remark2` varchar(200) NOT NULL DEFAULT '', `remark3` varchar(200) NOT NULL DEFAULT '', `remark4` varchar(200) NOT NULL DEFAULT '', `remark5` varchar(200) NOT NULL DEFAULT '', `remark6` varchar(200) NOT NULL DEFAULT '', PRIMARY KEY (`idpk`)) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;";
const cmdtext2 = "CREATE TABLE IF NOT EXISTS `sys_sql` ( `cid` varchar(36) NOT NULL DEFAULT '', `apiv` varchar(50) NOT NULL DEFAULT '', `apisys` varchar(50) NOT NULL DEFAULT '', `apiobj` varchar(50) NOT NULL DEFAULT '', `cmdtext` varchar(200) NOT NULL, `uname` varchar(50) NOT NULL DEFAULT '', `num` int(11) NOT NULL DEFAULT '0', `dlong` int(32) NOT NULL DEFAULT '0', `downlen` bigint NOT NULL DEFAULT '0', `upby` varchar(50) NOT NULL DEFAULT '', `cmdtextmd5` varchar(50) NOT NULL DEFAULT '', `uptime` datetime NOT NULL, `idpk` int(11) NOT NULL AUTO_INCREMENT, `id` varchar(36) NOT NULL, `remark` varchar(200) NOT NULL DEFAULT '', `remark2` varchar(200) NOT NULL DEFAULT '', `remark3` varchar(200) NOT NULL DEFAULT '', `remark4` varchar(200) NOT NULL DEFAULT '', `remark5` varchar(200) NOT NULL DEFAULT '', `remark6` varchar(200) NOT NULL DEFAULT '', PRIMARY KEY (`idpk`), UNIQUE KEY `u_v_sys_obj_cmdtext` (`apiv`,`apisys`,`apiobj`,`cmdtext`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;";
try {
yield this._pool.execute(cmdtext1);
yield this._pool.execute(cmdtext2);
return 'ok';
}
catch (err) {
this.log.error(err);
return 'error';
}
});
}
getStatement(connection, cmdtext) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const cacheKey = `${connection.threadId}:${cmdtext}`;
if (this._statementCache.has(cacheKey)) {
return this._statementCache.get(cacheKey);
}
const statement = yield connection.prepare(cmdtext);
this._statementCache.set(cacheKey, statement);
return statement;
});
}
/**
* sql get
* @param cmdtext sql
* @param values
* @param up user upload
*/
doGet(cmdtext, values, up) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
var _a;
if (!this._pool) {
return [];
}
const debug = (_a = up.debug) !== null && _a !== void 0 ? _a : false;
const dstart = new Date();
let connection = null;
let statement = null;
try {
connection = yield this.retryOperation(() => this.getConnectionWithRetry());
if (!connection) {
throw new Error("Failed to get a valid connection.");
}
statement = yield this.getStatement(connection, cmdtext);
const [rows] = yield statement.execute(values);
const back = rows;
if (debug) {
this._addWarn(JSON.stringify(back) + " c:" + cmdtext + " v" + values.join(","), "debug_" + up.apisys, up);
}
const lendown = JSON.stringify(back).length;
this._saveLog(cmdtext, values, new Date().getTime() - dstart.getTime(), lendown, up);
return back;
}
catch (err) {
this._addWarn(JSON.stringify(err) + " c:" + cmdtext + " v" + values.join(","), "err_" + up.apisys, up);
this.log.error(err, 'mysql_doGet');
throw err;
}
finally {
// if (statement) {
// await statement.close(); // 确保预处理语句被关闭
// }
if (connection) {
connection.release(); // 确保连接被释放
}
}
});
}
doT(cmds, values, errtexts, logtext, logvalue, up) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
var _a;
if (!this._pool) {
return 'pool null';
}
const debug = (_a = up.debug) !== null && _a !== void 0 ? _a : false;
const dstart = new Date();
let connection = null;
try {
connection = yield this.retryOperation(() => this.getConnectionWithRetry());
if (!connection) {
throw new Error("Failed to get a valid connection.");
}
yield connection.beginTransaction();
const promises = [];
for (let i = 0; i < cmds.length; i++) {
promises.push(this.doTran(cmds[i], values[i], connection, up));
}
const results = yield Promise.all(promises);
let errmsg = "err!";
let haveAff0 = false;
for (let i = 0; i < results.length; i++) {
if (results[i].affectedRows === 0) {
errmsg += errtexts[i];
haveAff0 = true;
break;
}
}
if (haveAff0 || results.length < cmds.length) {
yield connection.rollback();
connection.release();
return errmsg;
}
yield connection.commit();
connection.release();
this._saveLog(logtext, logvalue, new Date().getTime() - dstart.getTime(), 1, up);
return "ok";
}
catch (err) {
if (connection) {
yield connection.rollback();
connection.release();
}
this.log.error(err, 'mysql_doT');
return 'error';
}
});
}
/**
* sql update Method returns the full result set
* @param cmdtext sql
* @param values
* @param up user upload
*/
doMBack(cmdtext, values, up) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
var _a;
if (!this._pool) {
return {};
}
const debug = (_a = up.debug) !== null && _a !== void 0 ? _a : false;
const dstart = new Date();
let connection = null;
let statement = null;
try {
connection = yield this.retryOperation(() => this.getConnectionWithRetry());
if (!connection) {
throw new Error("Failed to get a valid connection.");
}
statement = yield this.getStatement(connection, cmdtext);
const [result] = yield statement.execute(values);
if (debug) {
this._addWarn(JSON.stringify(result) + " c:" + cmdtext + " v" + values.join(","), "debug_" + up.apisys, up);
}
const lendown = JSON.stringify(result).length;
this._saveLog(cmdtext, values, new Date().getTime() - dstart.getTime(), lendown, up);
return result;
}
catch (err) {
this._addWarn(JSON.stringify(err) + " c:" + cmdtext + " v" + values.join(","), "err" + up.apisys, up);
this.log.error(err, 'mysql_doM');
return {};
}
finally {
// if (statement) {
// await statement.close(); // 确保预处理语句被关闭
// }
if (connection) {
connection.release(); // 确保连接被释放
}
}
});
}
/**
* sql update Method returns the number of affected rows
* @param cmdtext sql
* @param values
* @param up user upload
*/
doM(cmdtext, values, up) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
var _a;
if (!this._pool) {
return 0;
}
const debug = (_a = up.debug) !== null && _a !== void 0 ? _a : false;
const dstart = new Date();
let connection = null;
let statement = null;
try {
connection = yield this.retryOperation(() => this.getConnectionWithRetry());
if (!connection) {
throw new Error("Failed to get a valid connection.");
}
statement = yield this.getStatement(connection, cmdtext);
const [result] = yield statement.execute(values);
const affectedRows = result.affectedRows;
if (debug) {
this._addWarn(JSON.stringify(result) + " c:" + cmdtext + " v" + values.join(","), "debug_" + up.apisys, up);
}
const lendown = JSON.stringify(result).length;
this._saveLog(cmdtext, values, new Date().getTime() - dstart.getTime(), lendown, up);
return affectedRows;
}
catch (err) {
this._addWarn(JSON.stringify(err) + " c:" + cmdtext + " v" + values.join(","), "err" + up.apisys, up);
this.log.error(err, `mysql_doM cmdtext: ${cmdtext} values: ${JSON.stringify(values)}`);
return -1;
}
finally {
// if (statement) {
// await statement.close(); // 确保预处理语句被关闭
// }
if (connection) {
connection.release(); // 确保连接被释放
}
}
});
}
/**
* Inserting a row returns the inserted row number
* @param cmdtext
* @param values
* @param up
*/
doMAdd(cmdtext, values, up) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
var _a;
if (!this._pool) {
return 0;
}
const debug = (_a = up.debug) !== null && _a !== void 0 ? _a : false;
const dstart = new Date();
try {
const [result] = yield this._pool.execute(cmdtext, values);
const insertId = result.insertId;
if (debug) {
this._addWarn(JSON.stringify(result) + " c:" + cmdtext + " v" + values.join(","), "debug_" + up.apisys, up);
}
const lendown = JSON.stringify(result).length;
this._saveLog(cmdtext, values, new Date().getTime() - dstart.getTime(), lendown, up);
return insertId;
}
catch (err) {
this._addWarn(JSON.stringify(err) + " c:" + cmdtext + " v" + values.join(","), "err" + up.apisys, up);
this.log.error(err, 'mysql_doMAdd');
return 0;
}
});
}
/**
* Transactions are executed piecemeal (it is usually better not to use doT)
* You need to release the connection yourself
* There may be complicated scenarios where the first sentence is successful but what condition has changed and you still need to roll back the transaction
* @param cmdtext
* @param values
* @param con
* @param up
*/
doTran(cmdtext, values, con, up) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
var _a;
const debug = (_a = up.debug) !== null && _a !== void 0 ? _a : false;
try {
const [result] = yield con.execute(cmdtext, values);
if (debug) {
this.log.info(`${cmdtext} v:${values.join(",")} r:${JSON.stringify(result)} 0, 'mysql', 'doTran', ${up.uname}`, 0);
}
return result;
}
catch (err) {
this.log.error(err, 'mysql_doTran');
throw err;
}
});
}
/**
* doget doM does not need to be released manually
* getConnection
* */
releaseConnection(client) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (this._pool) {
this._pool.releaseConnection(client);
}
});
}
/**
* Get the connection (remember to release it)
* */
getConnection() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (!this._pool) {
return null;
}
try {
const connection = yield this._pool.getConnection();
return connection;
}
catch (err) {
this.log.error(err, 'mysql_getConnection');
return null;
}
});
}
/**
* 设置警告处理器
* @param handler 处理警告的函数
*/
setWarnHandler(handler) {
this.warnHandler = handler;
}
/**
* 调试函数,用于跟踪SQL调用的在线调试问题
* 可以设置跟踪用户、表、目录或函数等
* 开启会影响性能,建议主要用于跟踪开发者和正在开发的目录
* 如果设置了自定义的warnHandler,将优先使用它处理警告
* 否则,将警告信息插入sys_warn表
* @param info 日志信息
* @param kind 日志类型
* @param up 用户上传信息
*/
_addWarn(info, kind, up) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (this.warnHandler) {
try {
return yield this.warnHandler(info, kind, up);
}
catch (err) {
this.log.error(err, 'mysql__addWarn_handler');
}
}
if (!this._pool || !this.isLog) {
return this.isLog ? 'pool null' : 'isLog is false';
}
const cmdtext = 'INSERT INTO sys_warn (`kind`,apisys,apiobj,`content`,`upby`,`uptime`,`id`,upid)VALUES(?,?,?,?,?,?,?,?)';
const values = [kind, up.apisys, up.apiobj, info, up.uname, up.uptime, koa78_upinfo_1.default.getNewid(), up.upid];
try {
const [results] = yield this._pool.execute(cmdtext, values);
return results.affectedRows;
}
catch (err) {
this.log.error(err, 'mysql__addWarn');
return 0;
}
});
}
/**
* If the table name SYS_SQL is opened after the function, it will affect performance
* @param cmdtext SQL
* @param values
* @param dlong Function Timing
* @param lendown down bytes
* @param up user upload
*/
_saveLog(cmdtext, values, dlong, lendown, up) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (!this.isCount || !this._pool) {
return this.isCount ? 'pool null' : 'isCount is false';
}
const cmdtextmd5 = (0, md5_1.default)(cmdtext);
const sb = 'INSERT INTO sys_sql(apiv,apisys,apiobj,cmdtext,num,dlong,downlen,id,uptime,cmdtextmd5)VALUES(?,?,?,?,?,?,?,?,?,?) ' +
'ON DUPLICATE KEY UPDATE num=num+1,dlong=dlong+?,downlen=downlen+?';
try {
yield this._pool.execute(sb, [
up.v, up.apisys, up.apiobj, cmdtext, 1, dlong, lendown, koa78_upinfo_1.default.getNewid(), new Date(), cmdtextmd5,
dlong, lendown
]);
return 'ok';
}
catch (err) {
this.log.error(err);
return 'error';
}
});
}
close() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (this._pool) {
yield this._pool.end();
}
});
}
}
exports.default = Mysql78;
//# sourceMappingURL=index.js.map