Files
xiaocai/server/src/db/init.ts
wangxiaogang 418d5b24f9 fix: 迁移逻辑独立执行,不依赖 schema/seed 成功
问题:runMigrations 在 try 块内,如果 seed 失败则迁移不执行
修复:将迁移逻辑移到独立的 try-catch 块,确保始终执行
添加详细日志帮助调试
2026-05-29 17:07:41 +08:00

95 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import mysql from 'mysql2/promise'
import pool from './connection'
import { readFileSync } from 'fs'
import { join } from 'path'
async function columnExists(conn: mysql.Connection, table: string, column: string): Promise<boolean> {
const [rows] = await conn.query(
`SELECT COUNT(*) as cnt FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?`,
[table, column]
)
return (rows as any[])[0].cnt > 0
}
async function runMigrations(conn: mysql.Connection) {
console.log('[DB] Checking migrations...')
// transactions 表添加 user_id
const hasTxUserId = await columnExists(conn, 'transactions', 'user_id')
console.log(`[DB] transactions.user_id exists: ${hasTxUserId}`)
if (!hasTxUserId) {
console.log('[DB] Migrating: adding user_id to transactions')
await conn.query('ALTER TABLE transactions ADD COLUMN user_id INT NOT NULL DEFAULT 1 AFTER id')
await conn.query('ALTER TABLE transactions ADD INDEX idx_user_date (user_id, date)')
await conn.query('ALTER TABLE transactions ADD INDEX idx_user_type_date (user_id, type, date)')
console.log('[DB] transactions.user_id added')
}
// budgets 表添加 user_id
const hasBudgetUserId = await columnExists(conn, 'budgets', 'user_id')
console.log(`[DB] budgets.user_id exists: ${hasBudgetUserId}`)
if (!hasBudgetUserId) {
console.log('[DB] Migrating: adding user_id to budgets')
await conn.query('ALTER TABLE budgets ADD COLUMN user_id INT NOT NULL DEFAULT 1 AFTER id')
await conn.query('ALTER TABLE budgets ADD UNIQUE KEY uk_user_month (user_id, month)')
console.log('[DB] budgets.user_id added')
}
}
export async function initDatabase() {
const dbName = process.env.DB_NAME || 'xiaocai'
// 先用不指定数据库的连接,确保数据库存在
const bootstrap = await mysql.createConnection({
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'xiaocai',
password: process.env.DB_PASSWORD || 'xiaocai123',
multipleStatements: true,
})
await bootstrap.query(`CREATE DATABASE IF NOT EXISTS \`${dbName}\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`)
await bootstrap.end()
// 用独立连接执行建表和填充(需要 multipleStatements
const initConn = await mysql.createConnection({
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'xiaocai',
password: process.env.DB_PASSWORD || 'xiaocai123',
database: dbName,
multipleStatements: true,
})
try {
const schemaPath = join(__dirname, 'schema.sql')
const seedPath = join(__dirname, 'seed.sql')
const schema = readFileSync(schemaPath, 'utf-8')
const cleanSchema = schema
.replace(/CREATE DATABASE.*?;/gi, '')
.replace(/USE\s+\w+;/gi, '')
await initConn.query(cleanSchema)
const seed = readFileSync(seedPath, 'utf-8')
await initConn.query(seed)
console.log('[DB] Schema and seed applied')
} catch (err: any) {
if (err.code === 'ER_DUP_ENTRY' || err.errno === 1062) {
console.log('[DB] Already initialized, skipping seed')
} else {
console.error('[DB] Init warning:', err.message)
}
}
// 始终运行迁移(独立于 schema/seed
try {
await runMigrations(initConn)
console.log('[DB] Migrations complete')
} catch (err: any) {
console.error('[DB] Migration error:', err.message)
}
await initConn.end()
console.log('[DB] Database ready')
}