docs: 完善项目说明和注释
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { createConnection } from "mysql2/promise";
|
||||
import { env } from "../config/env";
|
||||
|
||||
// 迁移脚本使用单独连接而不是连接池,因为它是一次性命令,不是长时间运行的 HTTP 服务。
|
||||
async function migrate(): Promise<void> {
|
||||
const connection = await createConnection({
|
||||
host: env.DB_HOST,
|
||||
port: env.DB_PORT,
|
||||
user: env.DB_USER,
|
||||
password: env.DB_PASSWORD,
|
||||
database: env.DB_NAME,
|
||||
// 迁移文件里可能包含多个 CREATE TABLE / INSERT 语句,所以需要允许多语句执行。
|
||||
multipleStatements: true,
|
||||
timezone: "+08:00"
|
||||
});
|
||||
|
||||
try {
|
||||
// schema_migrations 记录每个已经执行过的 SQL 文件名。
|
||||
// 之后重复运行 pnpm db:migrate 时,已执行过的迁移会被跳过。
|
||||
await connection.query(`
|
||||
CREATE TABLE IF NOT EXISTS schema_migrations (
|
||||
version VARCHAR(255) NOT NULL,
|
||||
applied_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (version)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='数据库迁移记录表';
|
||||
`);
|
||||
|
||||
const migrationsDir = path.resolve(process.cwd(), "migrations");
|
||||
const files = (await fs.readdir(migrationsDir))
|
||||
.filter((file) => file.endsWith(".sql"))
|
||||
.sort();
|
||||
|
||||
for (const file of files) {
|
||||
// 以文件名作为版本号,简单直观,适合这个学习项目。
|
||||
const [rows] = await connection.query(
|
||||
"SELECT version FROM schema_migrations WHERE version = ? LIMIT 1",
|
||||
[file]
|
||||
);
|
||||
|
||||
if (Array.isArray(rows) && rows.length > 0) {
|
||||
console.log(`跳过已执行迁移:${file}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const sql = await fs.readFile(path.join(migrationsDir, file), "utf8");
|
||||
|
||||
// 迁移文件按文件名顺序执行,便于团队协作时追踪每一次表结构变化。
|
||||
await connection.query(sql);
|
||||
await connection.query("INSERT INTO schema_migrations (version) VALUES (?)", [file]);
|
||||
console.log(`已执行迁移:${file}`);
|
||||
}
|
||||
} finally {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
|
||||
migrate().catch((error: unknown) => {
|
||||
console.error("数据库迁移失败:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import { createPool } from "mysql2/promise";
|
||||
import { env } from "../config/env";
|
||||
|
||||
// 企业项目里不要每次请求都创建连接。连接池负责复用连接,并限制最大并发连接数。
|
||||
export const pool = createPool({
|
||||
host: env.DB_HOST,
|
||||
port: env.DB_PORT,
|
||||
user: env.DB_USER,
|
||||
password: env.DB_PASSWORD,
|
||||
database: env.DB_NAME,
|
||||
waitForConnections: true,
|
||||
connectionLimit: env.DB_CONNECTION_LIMIT,
|
||||
namedPlaceholders: true,
|
||||
timezone: "+08:00",
|
||||
});
|
||||
|
||||
// pingDatabase 用于健康检查,确保数据库连接正常。
|
||||
export async function pingDatabase(): Promise<void> {
|
||||
const connection = await pool.getConnection();
|
||||
try {
|
||||
await connection.ping();
|
||||
} finally {
|
||||
// getConnection 取出的连接必须 release,才能放回连接池继续复用。
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
|
||||
// closeDatabase 在服务停机时调用,确保所有连接都被正确关闭,避免资源泄漏。
|
||||
export async function closeDatabase(): Promise<void> {
|
||||
await pool.end();
|
||||
}
|
||||
Reference in New Issue
Block a user