| 
									
										
										
										
											2025-09-24 10:02:03 +08:00
										 |  |  |  | const mysql = require('mysql2/promise'); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 数据库配置
 | 
					
						
							|  |  |  |  | const dbConfig = { | 
					
						
							|  |  |  |  |     // host: process.env.DB_HOST || '114.55.111.44',
 | 
					
						
							|  |  |  |  |     // user: process.env.DB_USER || 'maov2',
 | 
					
						
							|  |  |  |  |     // password: process.env.DB_PASSWORD || '5fYhw8z6T62b7heS',
 | 
					
						
							|  |  |  |  |     // database: process.env.DB_NAME || 'maov2',
 | 
					
						
							|  |  |  |  |     host: '114.55.111.44', | 
					
						
							|  |  |  |  |     user: 'test_mao', | 
					
						
							|  |  |  |  |     password: 'nK2mPbWriBp25BRd', | 
					
						
							|  |  |  |  |     database: 'test_mao', | 
					
						
							|  |  |  |  |     charset: 'utf8mb4', | 
					
						
							|  |  |  |  |     dateStrings: true, | 
					
						
							|  |  |  |  |     // 连接池配置
 | 
					
						
							|  |  |  |  |     connectionLimit: 20, // 连接池最大连接数
 | 
					
						
							| 
									
										
										
										
											2025-09-26 14:38:44 +08:00
										 |  |  |  |     // queueLimit: 0, // 排队等待连接的最大数量,0表示无限制
 | 
					
						
							| 
									
										
										
										
											2025-09-24 10:02:03 +08:00
										 |  |  |  |     // 连接超时配置
 | 
					
						
							|  |  |  |  |     // acquireTimeout: 60000, // 获取连接超时时间 60秒
 | 
					
						
							|  |  |  |  |     // timeout: 60000, // 查询超时时间 60秒
 | 
					
						
							|  |  |  |  |     // reconnect: true, // 自动重连
 | 
					
						
							|  |  |  |  |     // 连接保活配置
 | 
					
						
							|  |  |  |  |     // multipleStatements: true,
 | 
					
						
							|  |  |  |  |     // 空闲连接超时配置
 | 
					
						
							|  |  |  |  |     // idleTimeout: 300000, // 5分钟空闲超时
 | 
					
						
							|  |  |  |  |     // maxLifetime: 1800000, // 30分钟最大生命周期
 | 
					
						
							|  |  |  |  |     // 连接保活设置
 | 
					
						
							|  |  |  |  |     // keepAliveInitialDelay: 0, // 开始保活探测前的延迟时间
 | 
					
						
							|  |  |  |  |     // enableKeepAlive: true, // 启用TCP保活
 | 
					
						
							|  |  |  |  |     // 添加类型转换配置
 | 
					
						
							|  |  |  |  |     typeCast: function (field, next) { | 
					
						
							|  |  |  |  |         if (field.type === 'TINY' && field.length === 1) { | 
					
						
							|  |  |  |  |             return (field.string() === '1'); // 1 = true, 0 = false
 | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return next(); | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  |     // 确保参数正确处理
 | 
					
						
							|  |  |  |  |     supportBigNumbers: true, | 
					
						
							|  |  |  |  |     bigNumberStrings: false | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 创建数据库连接池
 | 
					
						
							|  |  |  |  | let pool; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /** | 
					
						
							|  |  |  |  |  * 初始化数据库连接池 | 
					
						
							|  |  |  |  |  * @returns {Promise<mysql.Pool>} 数据库连接池 | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | async function initDB() { | 
					
						
							|  |  |  |  |     if (!pool) { | 
					
						
							|  |  |  |  |         try { | 
					
						
							|  |  |  |  |             pool = mysql.createPool(dbConfig); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 添加连接池事件监听
 | 
					
						
							|  |  |  |  |             pool.on('connection', function (connection) { | 
					
						
							|  |  |  |  |                 console.log('新的数据库连接建立:', connection.threadId); | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 注释掉频繁的连接获取和释放日志,避免日志过多
 | 
					
						
							|  |  |  |  |             // pool.on('acquire', function (connection) {
 | 
					
						
							|  |  |  |  |             //   console.log('连接池获取连接:', connection.threadId);
 | 
					
						
							|  |  |  |  |             // });
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // pool.on('release', function (connection) {
 | 
					
						
							|  |  |  |  |             //   console.log('连接池释放连接:', connection.threadId);
 | 
					
						
							|  |  |  |  |             // });
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             pool.on('error', function (err) { | 
					
						
							|  |  |  |  |                 console.error('数据库连接池错误:', err); | 
					
						
							|  |  |  |  |                 if (err.code === 'PROTOCOL_CONNECTION_LOST') { | 
					
						
							|  |  |  |  |                     console.log('数据库连接丢失,尝试重新连接...'); | 
					
						
							|  |  |  |  |                 } else if (err.code === 'ECONNRESET') { | 
					
						
							|  |  |  |  |                     console.log('数据库连接被重置,尝试重新连接...'); | 
					
						
							|  |  |  |  |                 } else if (err.code === 'ETIMEDOUT') { | 
					
						
							|  |  |  |  |                     console.log('数据库连接超时,尝试重新连接...'); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 测试连接
 | 
					
						
							|  |  |  |  |             const connection = await pool.getConnection(); | 
					
						
							|  |  |  |  |             console.log('数据库连接池初始化成功'); | 
					
						
							|  |  |  |  |             connection.release(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         } catch (error) { | 
					
						
							|  |  |  |  |             console.error('数据库连接池初始化失败:', error); | 
					
						
							|  |  |  |  |             throw error; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return pool; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /** | 
					
						
							|  |  |  |  |  * 获取数据库连接池 | 
					
						
							|  |  |  |  |  * @returns {mysql.Pool} 数据库连接池 | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | function getDB() { | 
					
						
							|  |  |  |  |     if (!pool) { | 
					
						
							|  |  |  |  |         throw new Error('数据库连接池未初始化,请先调用 initDB()'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return pool; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /** | 
					
						
							|  |  |  |  |  * 执行数据库查询(带重试机制) | 
					
						
							|  |  |  |  |  * @param {string} sql SQL查询语句 | 
					
						
							|  |  |  |  |  * @param {Array} params 查询参数 | 
					
						
							|  |  |  |  |  * @param {number} retries 重试次数 | 
					
						
							|  |  |  |  |  * @returns {Promise<Array>} 查询结果 | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | async function executeQuery(sql, params = [], retries = 3) { | 
					
						
							|  |  |  |  |     for (let i = 0; i < retries; i++) { | 
					
						
							|  |  |  |  |         try { | 
					
						
							|  |  |  |  |             const connection = await pool.getConnection(); | 
					
						
							|  |  |  |  |             try { | 
					
						
							|  |  |  |  |                 const [results] = await connection.execute(sql, params); | 
					
						
							|  |  |  |  |                 connection.release(); | 
					
						
							|  |  |  |  |                 return results; | 
					
						
							|  |  |  |  |             } catch (error) { | 
					
						
							|  |  |  |  |                 connection.release(); | 
					
						
							|  |  |  |  |                 throw error; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } catch (error) { | 
					
						
							|  |  |  |  |             console.error(`数据库查询失败 (尝试 ${i + 1}/${retries}):`, error.message); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (i === retries - 1) { | 
					
						
							|  |  |  |  |                 throw error; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 如果是连接相关错误,等待后重试
 | 
					
						
							|  |  |  |  |             if (error.code === 'PROTOCOL_CONNECTION_LOST' || | 
					
						
							|  |  |  |  |                 error.code === 'ECONNRESET' || | 
					
						
							|  |  |  |  |                 error.code === 'ETIMEDOUT') { | 
					
						
							|  |  |  |  |                 console.log(`等待 ${(i + 1) * 1000}ms 后重试...`); | 
					
						
							|  |  |  |  |                 await new Promise(resolve => setTimeout(resolve, (i + 1) * 1000)); | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 throw error; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /** | 
					
						
							|  |  |  |  |  * 关闭数据库连接池 | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | async function closeDB() { | 
					
						
							|  |  |  |  |     if (pool) { | 
					
						
							|  |  |  |  |         await pool.end(); | 
					
						
							|  |  |  |  |         pool = null; | 
					
						
							|  |  |  |  |         console.log('数据库连接池已关闭'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | module.exports = { | 
					
						
							|  |  |  |  |     initDB, | 
					
						
							|  |  |  |  |     getDB, | 
					
						
							|  |  |  |  |     closeDB, | 
					
						
							|  |  |  |  |     executeQuery, | 
					
						
							|  |  |  |  |     dbConfig | 
					
						
							|  |  |  |  | }; |