更新项目文件结构,统一文档风格
This commit is contained in:
205
backend/database/setup-database.js
Normal file
205
backend/database/setup-database.js
Normal file
@@ -0,0 +1,205 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
require('dotenv').config();
|
||||
|
||||
class DatabaseSetup {
|
||||
constructor() {
|
||||
this.config = {
|
||||
host: process.env.DB_HOST,
|
||||
port: parseInt(process.env.DB_PORT),
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
multipleStatements: true
|
||||
};
|
||||
}
|
||||
|
||||
async checkConnection() {
|
||||
console.log('🔍 检查数据库连接...');
|
||||
console.log(`📍 服务器: ${this.config.host}:${this.config.port}`);
|
||||
console.log(`👤 用户: ${this.config.user}`);
|
||||
console.log(`🗄️ 数据库: ${this.config.database}`);
|
||||
|
||||
try {
|
||||
const connection = await mysql.createConnection(this.config);
|
||||
console.log('✅ 数据库连接成功!');
|
||||
|
||||
// 获取数据库版本信息
|
||||
const [version] = await connection.execute('SELECT VERSION() as version');
|
||||
console.log(`📋 MySQL版本: ${version[0].version}`);
|
||||
|
||||
await connection.end();
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('❌ 数据库连接失败:', error.message);
|
||||
|
||||
if (error.code === 'ER_ACCESS_DENIED_ERROR') {
|
||||
console.log('\n💡 可能的解决方案:');
|
||||
console.log('1. 检查用户名和密码是否正确');
|
||||
console.log('2. 确认用户有访问该数据库的权限');
|
||||
console.log('3. 检查IP白名单是否包含当前服务器IP');
|
||||
console.log(` 当前尝试连接的IP需要添加到腾讯云数据库白名单中`);
|
||||
} else if (error.code === 'ENOTFOUND') {
|
||||
console.log('\n💡 域名解析失败,请检查:');
|
||||
console.log('1. 数据库服务器地址是否正确');
|
||||
console.log('2. 网络连接是否正常');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async executeSQL(sqlFile) {
|
||||
console.log(`\n📄 执行SQL文件: ${sqlFile}`);
|
||||
|
||||
try {
|
||||
const sqlPath = path.join(__dirname, sqlFile);
|
||||
const sql = fs.readFileSync(sqlPath, 'utf8');
|
||||
|
||||
const connection = await mysql.createConnection(this.config);
|
||||
|
||||
// 分割SQL语句并逐个执行
|
||||
const statements = sql.split(';').filter(stmt => stmt.trim().length > 0);
|
||||
let successCount = 0;
|
||||
|
||||
for (const statement of statements) {
|
||||
const trimmedStmt = statement.trim();
|
||||
if (trimmedStmt) {
|
||||
try {
|
||||
await connection.execute(trimmedStmt);
|
||||
successCount++;
|
||||
} catch (error) {
|
||||
if (!error.message.includes('already exists')) {
|
||||
console.warn(`⚠️ 执行语句时警告: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ 成功执行 ${successCount} 条SQL语句`);
|
||||
await connection.end();
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ 执行SQL文件失败: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async checkTables() {
|
||||
console.log('\n📋 检查数据库表结构...');
|
||||
|
||||
try {
|
||||
const connection = await mysql.createConnection(this.config);
|
||||
|
||||
// 获取所有表
|
||||
const [tables] = await connection.execute(
|
||||
'SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?',
|
||||
[this.config.database]
|
||||
);
|
||||
|
||||
console.log(`📊 数据库 ${this.config.database} 中共有 ${tables.length} 张表:`);
|
||||
|
||||
tables.forEach((table, index) => {
|
||||
console.log(` ${index + 1}. ${table.TABLE_NAME} - ${table.TABLE_COMMENT || '无注释'}`);
|
||||
});
|
||||
|
||||
// 检查重要表是否存在
|
||||
const requiredTables = ['users', 'cattle', 'loan_applications', 'insurance_applications', 'contracts', 'products', 'orders'];
|
||||
const existingTables = tables.map(t => t.TABLE_NAME);
|
||||
const missingTables = requiredTables.filter(table => !existingTables.includes(table));
|
||||
|
||||
if (missingTables.length === 0) {
|
||||
console.log('✅ 所有核心表已创建');
|
||||
} else {
|
||||
console.log(`⚠️ 缺少核心表: ${missingTables.join(', ')}`);
|
||||
}
|
||||
|
||||
await connection.end();
|
||||
return { tables: existingTables, missing: missingTables };
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 检查表结构失败:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async getMyIPAddress() {
|
||||
try {
|
||||
const https = require('https');
|
||||
return new Promise((resolve, reject) => {
|
||||
https.get('https://api.ipify.org', (resp) => {
|
||||
let data = '';
|
||||
resp.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
resp.on('end', () => {
|
||||
resolve(data);
|
||||
});
|
||||
}).on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
return '无法获取';
|
||||
}
|
||||
}
|
||||
|
||||
async setup() {
|
||||
console.log('🚀 开始数据库初始化流程...\n');
|
||||
|
||||
// 获取当前IP地址
|
||||
const myIP = await this.getMyIPAddress();
|
||||
console.log(`🌐 当前公网IP地址: ${myIP}`);
|
||||
console.log('📝 请确保此IP已添加到腾讯云数据库白名单中\n');
|
||||
|
||||
// 检查连接
|
||||
const connected = await this.checkConnection();
|
||||
if (!connected) {
|
||||
console.log('\n❌ 数据库连接失败,请先解决连接问题');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 执行基础表创建
|
||||
console.log('\n🔨 创建基础表结构...');
|
||||
const basicResult = await this.executeSQL('init_tables.sql');
|
||||
if (!basicResult) {
|
||||
console.log('❌ 基础表创建失败');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 执行扩展表创建
|
||||
console.log('\n🔧 创建扩展表结构...');
|
||||
const extendedResult = await this.executeSQL('init_tables_extended.sql');
|
||||
if (!extendedResult) {
|
||||
console.log('❌ 扩展表创建失败');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证表结构
|
||||
await this.checkTables();
|
||||
|
||||
console.log('\n🎉 数据库初始化完成!');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此脚本
|
||||
if (require.main === module) {
|
||||
const setup = new DatabaseSetup();
|
||||
setup.setup().then((success) => {
|
||||
if (success) {
|
||||
console.log('\n✅ 数据库设置成功完成');
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.log('\n❌ 数据库设置失败');
|
||||
process.exit(1);
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('💥 发生错误:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = DatabaseSetup;
|
||||
Reference in New Issue
Block a user