138 lines
3.4 KiB
JavaScript
138 lines
3.4 KiB
JavaScript
|
|
// 数据库管理器模块
|
||
|
|
import { Pool } from 'pg';
|
||
|
|
|
||
|
|
class DatabaseManager {
|
||
|
|
constructor(config) {
|
||
|
|
this.config = config;
|
||
|
|
this.pool = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
async connect() {
|
||
|
|
try {
|
||
|
|
// 创建数据库连接池
|
||
|
|
this.pool = new Pool(this.config);
|
||
|
|
|
||
|
|
// 测试连接
|
||
|
|
await this.pool.connect();
|
||
|
|
console.log('数据库连接池创建成功');
|
||
|
|
|
||
|
|
// 初始化表结构
|
||
|
|
await this.initTables();
|
||
|
|
} catch (error) {
|
||
|
|
console.error('数据库连接失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async disconnect() {
|
||
|
|
try {
|
||
|
|
if (this.pool) {
|
||
|
|
await this.pool.end();
|
||
|
|
console.log('数据库连接池已关闭');
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error('关闭数据库连接池失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async initTables() {
|
||
|
|
try {
|
||
|
|
const createTableQuery = `
|
||
|
|
CREATE TABLE IF NOT EXISTS heartbeat (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
component_id VARCHAR(50) NOT NULL,
|
||
|
|
status VARCHAR(20) NOT NULL,
|
||
|
|
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
data JSONB,
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_heartbeat_component_id ON heartbeat(component_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_heartbeat_timestamp ON heartbeat(timestamp);
|
||
|
|
`;
|
||
|
|
|
||
|
|
await this.pool.query(createTableQuery);
|
||
|
|
console.log('数据库表初始化成功');
|
||
|
|
} catch (error) {
|
||
|
|
console.error('数据库表初始化失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async insertHeartbeatData(data) {
|
||
|
|
try {
|
||
|
|
if (!Array.isArray(data)) {
|
||
|
|
data = [data];
|
||
|
|
}
|
||
|
|
|
||
|
|
if (data.length === 0) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 构建批量插入语句
|
||
|
|
const values = data.map(item => [
|
||
|
|
item.component_id,
|
||
|
|
item.status,
|
||
|
|
item.timestamp,
|
||
|
|
item.data
|
||
|
|
]);
|
||
|
|
|
||
|
|
const query = {
|
||
|
|
text: `
|
||
|
|
INSERT INTO heartbeat (component_id, status, timestamp, data)
|
||
|
|
VALUES ${values.map((_, index) => `($${index * 4 + 1}, $${index * 4 + 2}, $${index * 4 + 3}, $${index * 4 + 4})`).join(', ')}
|
||
|
|
`,
|
||
|
|
values: values.flat()
|
||
|
|
};
|
||
|
|
|
||
|
|
await this.pool.query(query);
|
||
|
|
console.log(`成功插入 ${data.length} 条心跳数据`);
|
||
|
|
} catch (error) {
|
||
|
|
console.error('插入心跳数据失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async getLatestHeartbeat(componentId) {
|
||
|
|
try {
|
||
|
|
const query = {
|
||
|
|
text: `
|
||
|
|
SELECT * FROM heartbeat
|
||
|
|
WHERE component_id = $1
|
||
|
|
ORDER BY timestamp DESC
|
||
|
|
LIMIT 1
|
||
|
|
`,
|
||
|
|
values: [componentId]
|
||
|
|
};
|
||
|
|
|
||
|
|
const result = await this.pool.query(query);
|
||
|
|
return result.rows[0] || null;
|
||
|
|
} catch (error) {
|
||
|
|
console.error('查询最新心跳数据失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async getHeartbeatHistory(componentId, startTime, endTime) {
|
||
|
|
try {
|
||
|
|
const query = {
|
||
|
|
text: `
|
||
|
|
SELECT * FROM heartbeat
|
||
|
|
WHERE component_id = $1
|
||
|
|
AND timestamp BETWEEN $2 AND $3
|
||
|
|
ORDER BY timestamp DESC
|
||
|
|
`,
|
||
|
|
values: [componentId, startTime, endTime]
|
||
|
|
};
|
||
|
|
|
||
|
|
const result = await this.pool.query(query);
|
||
|
|
return result.rows;
|
||
|
|
} catch (error) {
|
||
|
|
console.error('查询心跳历史数据失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export { DatabaseManager };
|