/** * 管理员数据迁移脚本 - Node.js * Feature: database-migration, Property 2: 数据记录数一致性 * Validates: Requirements 10.1 * * 源表: MySQL admin (3 条记录) * 目标表: SQL Server admins * * 注意: 管理日志表(admin_login_logs, admin_operation_logs)仅保留结构,不迁移数据 */ const mysql = require('mysql2/promise'); const sql = require('mssql'); // MySQL 配置 const mysqlConfig = { host: '192.168.195.16', port: 1887, user: 'root', password: 'Dbt@com@123', database: 'youdas', charset: 'utf8mb4' }; // SQL Server 配置 const sqlServerConfig = { server: '192.168.195.15', port: 1433, user: 'sa', password: 'Dbt@com@123', database: 'honey_box', options: { encrypt: false, trustServerCertificate: true } }; // Unix时间戳转换为 SQL Server DATETIME2 格式 function unixToDatetime(timestamp) { if (!timestamp || timestamp === 0) { return null; } const date = new Date(timestamp * 1000); return date.toISOString().slice(0, 23).replace('T', ' '); } // 转义SQL字符串 function escapeString(str) { if (str === null || str === undefined) return 'NULL'; return "N'" + String(str).replace(/'/g, "''") + "'"; } // 格式化日期时间 function formatDatetime(dt) { if (!dt) return 'NULL'; return "'" + dt + "'"; } // 获取已迁移的管理员ID列表 async function getMigratedIds(pool) { const result = await pool.request().query('SELECT id FROM admins'); return new Set(result.recordset.map(r => r.id)); } // 插入单条管理员数据 async function insertAdmin(pool, admin) { const createdAt = unixToDatetime(admin.addtime) || new Date().toISOString().slice(0, 23).replace('T', ' '); const updatedAt = unixToDatetime(admin.update_time) || createdAt; const getTime = unixToDatetime(admin.get_time) || createdAt; const sqlStatement = ` SET IDENTITY_INSERT admins ON; INSERT INTO admins ( id, username, nickname, password, qid, status, get_time, random, token, admin_id, created_at, updated_at ) VALUES ( ${admin.id}, ${escapeString(admin.username)}, ${escapeString(admin.nickname)}, ${escapeString(admin.password)}, ${admin.qid || 'NULL'}, ${admin.status || 0}, ${formatDatetime(getTime)}, ${escapeString(admin.random)}, ${escapeString(admin.token)}, ${admin.admin_id || 0}, ${formatDatetime(createdAt)}, ${formatDatetime(updatedAt)} ); SET IDENTITY_INSERT admins OFF;`; await pool.request().batch(sqlStatement); } async function main() { console.log('========================================'); console.log('管理员数据迁移脚本 - Node.js'); console.log('========================================\n'); let mysqlConn = null; let sqlPool = null; try { // 连接 MySQL console.log('正在连接 MySQL...'); mysqlConn = await mysql.createConnection(mysqlConfig); console.log('MySQL 连接成功\n'); // 连接 SQL Server console.log('正在连接 SQL Server...'); sqlPool = await sql.connect(sqlServerConfig); console.log('SQL Server 连接成功\n'); // 获取已迁移的ID console.log('正在获取已迁移的管理员ID...'); const migratedIds = await getMigratedIds(sqlPool); console.log(`已迁移管理员数: ${migratedIds.size}\n`); // 从 MySQL 获取所有管理员数据 console.log('正在从 MySQL 读取管理员数据...'); const [rows] = await mysqlConn.execute(` SELECT id, username, nickname, password, qid, status, get_time, random, token, admin_id, addtime, update_time FROM admin ORDER BY id `); console.log(`MySQL 管理员总数: ${rows.length}\n`); // 过滤出未迁移的管理员 const adminsToMigrate = rows.filter(admin => !migratedIds.has(admin.id)); console.log(`待迁移管理员数: ${adminsToMigrate.length}\n`); if (adminsToMigrate.length === 0) { console.log('所有管理员数据已迁移完成!'); } else { // 逐条迁移(数据量小,无需批量) let totalInserted = 0; for (const admin of adminsToMigrate) { try { await insertAdmin(sqlPool, admin); totalInserted++; console.log(`已迁移管理员: ${admin.id} - ${admin.username}`); } catch (err) { console.error(`插入管理员 ${admin.id} 失败:`, err.message); } } console.log(`\n迁移完成!共插入 ${totalInserted} 条记录`); } // 验证迁移结果 console.log('\n========================================'); console.log('迁移结果验证'); console.log('========================================'); const [mysqlCount] = await mysqlConn.execute('SELECT COUNT(*) as count FROM admin'); const sqlResult = await sqlPool.request().query('SELECT COUNT(*) as count FROM admins'); console.log(`MySQL admin 表记录数: ${mysqlCount[0].count}`); console.log(`SQL Server admins 表记录数: ${sqlResult.recordset[0].count}`); if (mysqlCount[0].count === sqlResult.recordset[0].count) { console.log('\n✅ 数据迁移完成,记录数一致!'); } else { console.log(`\n⚠️ 记录数不一致,差异: ${mysqlCount[0].count - sqlResult.recordset[0].count}`); } // 显示迁移后的数据 console.log('\n========================================'); console.log('迁移后的管理员数据'); console.log('========================================'); const adminsResult = await sqlPool.request().query('SELECT id, username, nickname, status FROM admins ORDER BY id'); for (const admin of adminsResult.recordset) { console.log(`ID: ${admin.id}, 用户名: ${admin.username}, 昵称: ${admin.nickname}, 状态: ${admin.status}`); } } catch (err) { console.error('迁移过程中发生错误:', err); process.exit(1); } finally { // 关闭连接 if (mysqlConn) await mysqlConn.end(); if (sqlPool) await sqlPool.close(); } } main();