// ===================================================== // 資料庫服務基類 - 確保連線正確關閉 // ===================================================== import { db } from './database'; import { PoolConnection } from 'mysql2/promise'; export abstract class DatabaseServiceBase { // 靜態安全查詢方法 - 每次查詢完就完全關閉連線 static async safeQuery(sql: string, params?: any[]): Promise { let connection: PoolConnection | null = null; try { // 獲取連線 connection = await db.getConnection(); // 執行查詢 const [rows] = await connection.execute(sql, params); // 完全關閉連線(不是釋放回連線池) await connection.destroy(); connection = null; console.log('✅ 靜態查詢連線已完全關閉'); return rows as T[]; } catch (error) { // 確保連線被關閉 if (connection) { try { await connection.destroy(); } catch (destroyError) { console.error('關閉靜態查詢連線時發生錯誤:', destroyError); } } throw error; } } // 實例安全查詢方法 - 每次查詢完就完全關閉連線 protected async safeQuery(sql: string, params?: any[]): Promise { let connection: PoolConnection | null = null; try { // 獲取連線 connection = await db.getConnection(); // 執行查詢 const [rows] = await connection.execute(sql, params); // 完全關閉連線(不是釋放回連線池) await connection.destroy(); connection = null; console.log('✅ 連線已完全關閉'); return rows as T[]; } catch (error) { // 確保連線被關閉 if (connection) { try { await connection.destroy(); } catch (destroyError) { console.error('關閉連線時發生錯誤:', destroyError); } } throw error; } } // 靜態安全單一查詢方法 static async safeQueryOne(sql: string, params?: any[]): Promise { const results = await DatabaseServiceBase.safeQuery(sql, params); return results.length > 0 ? results[0] : null; } // 實例安全單一查詢方法 protected async safeQueryOne(sql: string, params?: any[]): Promise { const results = await this.safeQuery(sql, params); return results.length > 0 ? results[0] : null; } // 靜態安全插入方法 - 每次查詢完就完全關閉連線 static async safeInsert(sql: string, params?: any[]): Promise { let connection: PoolConnection | null = null; try { connection = await db.getConnection(); const [result] = await connection.execute(sql, params); // 完全關閉連線 await connection.destroy(); connection = null; console.log('✅ 靜態插入連線已完全關閉'); return result; } catch (error) { if (connection) { try { await connection.destroy(); } catch (destroyError) { console.error('關閉靜態插入連線時發生錯誤:', destroyError); } } throw error; } } // 實例安全插入方法 - 每次查詢完就完全關閉連線 protected async safeInsert(sql: string, params?: any[]): Promise { let connection: PoolConnection | null = null; try { connection = await db.getConnection(); const [result] = await connection.execute(sql, params); // 完全關閉連線 await connection.destroy(); connection = null; console.log('✅ 實例插入連線已完全關閉'); return result; } catch (error) { if (connection) { try { await connection.destroy(); } catch (destroyError) { console.error('關閉實例插入連線時發生錯誤:', destroyError); } } throw error; } } // 靜態安全更新方法 - 每次查詢完就完全關閉連線 static async safeUpdate(sql: string, params?: any[]): Promise { let connection: PoolConnection | null = null; try { connection = await db.getConnection(); const [result] = await connection.execute(sql, params); // 完全關閉連線 await connection.destroy(); connection = null; console.log('✅ 靜態更新連線已完全關閉'); return result; } catch (error) { if (connection) { try { await connection.destroy(); } catch (destroyError) { console.error('關閉靜態更新連線時發生錯誤:', destroyError); } } throw error; } } // 實例安全更新方法 - 每次查詢完就完全關閉連線 protected async safeUpdate(sql: string, params?: any[]): Promise { let connection: PoolConnection | null = null; try { connection = await db.getConnection(); const [result] = await connection.execute(sql, params); // 完全關閉連線 await connection.destroy(); connection = null; console.log('✅ 實例更新連線已完全關閉'); return result; } catch (error) { if (connection) { try { await connection.destroy(); } catch (destroyError) { console.error('關閉實例更新連線時發生錯誤:', destroyError); } } throw error; } } // 靜態安全刪除方法 - 每次查詢完就完全關閉連線 static async safeDelete(sql: string, params?: any[]): Promise { let connection: PoolConnection | null = null; try { connection = await db.getConnection(); const [result] = await connection.execute(sql, params); // 完全關閉連線 await connection.destroy(); connection = null; console.log('✅ 靜態刪除連線已完全關閉'); return result; } catch (error) { if (connection) { try { await connection.destroy(); } catch (destroyError) { console.error('關閉靜態刪除連線時發生錯誤:', destroyError); } } throw error; } } // 實例安全刪除方法 - 每次查詢完就完全關閉連線 protected async safeDelete(sql: string, params?: any[]): Promise { let connection: PoolConnection | null = null; try { connection = await db.getConnection(); const [result] = await connection.execute(sql, params); // 完全關閉連線 await connection.destroy(); connection = null; console.log('✅ 實例刪除連線已完全關閉'); return result; } catch (error) { if (connection) { try { await connection.destroy(); } catch (destroyError) { console.error('關閉實例刪除連線時發生錯誤:', destroyError); } } throw error; } } // 事務處理方法 - 每次查詢完就完全關閉連線 protected async withTransaction( callback: (connection: PoolConnection) => Promise ): Promise { let connection: PoolConnection | null = null; try { connection = await db.getConnection(); await connection.beginTransaction(); const result = await callback(connection); await connection.commit(); // 完全關閉連線 await connection.destroy(); connection = null; console.log('✅ 事務連線已完全關閉'); return result; } catch (error) { if (connection) { try { await connection.rollback(); } catch (rollbackError) { console.error('回滾事務時發生錯誤:', rollbackError); } try { await connection.destroy(); } catch (destroyError) { console.error('關閉事務連線時發生錯誤:', destroyError); } } throw error; } } // 批次查詢方法 - 每次查詢完就完全關閉連線 protected async batchQuery( queries: Array<{ sql: string; params?: any[] }> ): Promise { let connection: PoolConnection | null = null; try { connection = await db.getConnection(); const results: T[][] = []; for (const query of queries) { const [rows] = await connection.execute(query.sql, query.params); results.push(rows as T[]); } // 完全關閉連線 await connection.destroy(); connection = null; console.log('✅ 批次查詢連線已完全關閉'); return results; } catch (error) { if (connection) { try { await connection.destroy(); } catch (destroyError) { console.error('關閉批次查詢連線時發生錯誤:', destroyError); } } throw error; } } // 連線健康檢查 protected async checkConnectionHealth(): Promise { try { await this.safeQueryOne('SELECT 1 as health_check'); return true; } catch (error) { console.error('資料庫連線健康檢查失敗:', error); return false; } } }