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