docs: 完善项目说明和注释

This commit is contained in:
湛兮
2026-05-26 11:06:13 +08:00
commit cd70caafbc
29 changed files with 3165 additions and 0 deletions
+62
View File
@@ -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);
});
+31
View File
@@ -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();
}