完成 APP 建立流程和使用分析、增加主機備機的備援機制、管理者後臺增加資料庫監控
This commit is contained in:
118
lib/database.ts
118
lib/database.ts
@@ -1,8 +1,10 @@
|
||||
// =====================================================
|
||||
// 資料庫連接配置
|
||||
// 資料庫連接配置 (整合備援功能)
|
||||
// =====================================================
|
||||
|
||||
import mysql from 'mysql2/promise';
|
||||
import { dbFailover } from './database-failover';
|
||||
import { dbSync } from './database-sync';
|
||||
|
||||
// 資料庫配置
|
||||
const dbConfig = {
|
||||
@@ -25,19 +27,21 @@ const dbConfig = {
|
||||
idleTimeout: 300000,
|
||||
maxIdle: 10,
|
||||
// 添加 SSL 配置(如果需要)
|
||||
ssl: false,
|
||||
ssl: false as any,
|
||||
};
|
||||
|
||||
// 創建連接池
|
||||
const pool = mysql.createPool(dbConfig);
|
||||
|
||||
// 資料庫連接類
|
||||
// 資料庫連接類 (整合備援功能)
|
||||
export class Database {
|
||||
private static instance: Database;
|
||||
private pool: mysql.Pool;
|
||||
private useFailover: boolean;
|
||||
|
||||
private constructor() {
|
||||
this.pool = pool;
|
||||
this.useFailover = process.env.DB_FAILOVER_ENABLED === 'true';
|
||||
}
|
||||
|
||||
public static getInstance(): Database {
|
||||
@@ -49,11 +53,18 @@ export class Database {
|
||||
|
||||
// 獲取連接
|
||||
public async getConnection(): Promise<mysql.PoolConnection> {
|
||||
if (this.useFailover) {
|
||||
return await dbFailover.getConnection();
|
||||
}
|
||||
return await this.pool.getConnection();
|
||||
}
|
||||
|
||||
// 執行查詢
|
||||
public async query<T = any>(sql: string, params?: any[]): Promise<T[]> {
|
||||
if (this.useFailover) {
|
||||
return await dbFailover.query<T>(sql, params);
|
||||
}
|
||||
|
||||
let connection;
|
||||
let retries = 0;
|
||||
const maxRetries = 3;
|
||||
@@ -92,6 +103,10 @@ export class Database {
|
||||
|
||||
// 執行單一查詢
|
||||
public async queryOne<T = any>(sql: string, params?: any[]): Promise<T | null> {
|
||||
if (this.useFailover) {
|
||||
return await dbFailover.queryOne<T>(sql, params);
|
||||
}
|
||||
|
||||
try {
|
||||
const results = await this.query<T>(sql, params);
|
||||
return results.length > 0 ? results[0] : null;
|
||||
@@ -101,8 +116,28 @@ export class Database {
|
||||
}
|
||||
}
|
||||
|
||||
// 執行插入
|
||||
// 執行插入(支援雙寫)
|
||||
public async insert(sql: string, params?: any[]): Promise<mysql.ResultSetHeader> {
|
||||
if (this.useFailover) {
|
||||
// 檢查是否啟用雙寫
|
||||
const syncStatus = await dbSync.getSyncStatus();
|
||||
if (syncStatus.enabled) {
|
||||
const result = await dbSync.dualInsert(sql, params);
|
||||
if (result.success) {
|
||||
// 返回主機的結果(如果主機成功)
|
||||
if (result.masterSuccess) {
|
||||
return await dbFailover.insert(sql, params);
|
||||
} else if (result.slaveSuccess) {
|
||||
// 如果只有備機成功,返回備機結果
|
||||
return await dbFailover.insert(sql, params);
|
||||
}
|
||||
}
|
||||
throw new Error(`雙寫失敗: 主機${result.masterError || '成功'}, 備機${result.slaveError || '成功'}`);
|
||||
} else {
|
||||
return await dbFailover.insert(sql, params);
|
||||
}
|
||||
}
|
||||
|
||||
const connection = await this.getConnection();
|
||||
try {
|
||||
const [result] = await connection.execute(sql, params);
|
||||
@@ -112,8 +147,28 @@ export class Database {
|
||||
}
|
||||
}
|
||||
|
||||
// 執行更新
|
||||
// 執行更新(支援雙寫)
|
||||
public async update(sql: string, params?: any[]): Promise<mysql.ResultSetHeader> {
|
||||
if (this.useFailover) {
|
||||
// 檢查是否啟用雙寫
|
||||
const syncStatus = await dbSync.getSyncStatus();
|
||||
if (syncStatus.enabled) {
|
||||
const result = await dbSync.dualUpdate(sql, params);
|
||||
if (result.success) {
|
||||
// 返回主機的結果(如果主機成功)
|
||||
if (result.masterSuccess) {
|
||||
return await dbFailover.update(sql, params);
|
||||
} else if (result.slaveSuccess) {
|
||||
// 如果只有備機成功,返回備機結果
|
||||
return await dbFailover.update(sql, params);
|
||||
}
|
||||
}
|
||||
throw new Error(`雙寫失敗: 主機${result.masterError || '成功'}, 備機${result.slaveError || '成功'}`);
|
||||
} else {
|
||||
return await dbFailover.update(sql, params);
|
||||
}
|
||||
}
|
||||
|
||||
const connection = await this.getConnection();
|
||||
try {
|
||||
const [result] = await connection.execute(sql, params);
|
||||
@@ -123,8 +178,28 @@ export class Database {
|
||||
}
|
||||
}
|
||||
|
||||
// 執行刪除
|
||||
// 執行刪除(支援雙寫)
|
||||
public async delete(sql: string, params?: any[]): Promise<mysql.ResultSetHeader> {
|
||||
if (this.useFailover) {
|
||||
// 檢查是否啟用雙寫
|
||||
const syncStatus = await dbSync.getSyncStatus();
|
||||
if (syncStatus.enabled) {
|
||||
const result = await dbSync.dualDelete(sql, params);
|
||||
if (result.success) {
|
||||
// 返回主機的結果(如果主機成功)
|
||||
if (result.masterSuccess) {
|
||||
return await dbFailover.delete(sql, params);
|
||||
} else if (result.slaveSuccess) {
|
||||
// 如果只有備機成功,返回備機結果
|
||||
return await dbFailover.delete(sql, params);
|
||||
}
|
||||
}
|
||||
throw new Error(`雙寫失敗: 主機${result.masterError || '成功'}, 備機${result.slaveError || '成功'}`);
|
||||
} else {
|
||||
return await dbFailover.delete(sql, params);
|
||||
}
|
||||
}
|
||||
|
||||
const connection = await this.getConnection();
|
||||
try {
|
||||
const [result] = await connection.execute(sql, params);
|
||||
@@ -136,6 +211,10 @@ export class Database {
|
||||
|
||||
// 開始事務
|
||||
public async beginTransaction(): Promise<mysql.PoolConnection> {
|
||||
if (this.useFailover) {
|
||||
return await dbFailover.beginTransaction();
|
||||
}
|
||||
|
||||
const connection = await this.getConnection();
|
||||
await connection.beginTransaction();
|
||||
return connection;
|
||||
@@ -143,18 +222,45 @@ export class Database {
|
||||
|
||||
// 提交事務
|
||||
public async commit(connection: mysql.PoolConnection): Promise<void> {
|
||||
if (this.useFailover) {
|
||||
return await dbFailover.commit(connection);
|
||||
}
|
||||
|
||||
await connection.commit();
|
||||
connection.release();
|
||||
}
|
||||
|
||||
// 回滾事務
|
||||
public async rollback(connection: mysql.PoolConnection): Promise<void> {
|
||||
if (this.useFailover) {
|
||||
return await dbFailover.rollback(connection);
|
||||
}
|
||||
|
||||
await connection.rollback();
|
||||
connection.release();
|
||||
}
|
||||
|
||||
// 獲取備援狀態
|
||||
public getFailoverStatus() {
|
||||
if (this.useFailover) {
|
||||
return dbFailover.getStatus();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 切換資料庫
|
||||
public async switchDatabase(database: 'master' | 'slave'): Promise<boolean> {
|
||||
if (this.useFailover) {
|
||||
return await dbFailover.switchToDatabase(database);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 關閉連接池
|
||||
public async close(): Promise<void> {
|
||||
if (this.useFailover) {
|
||||
await dbFailover.close();
|
||||
}
|
||||
await this.pool.end();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user