feat: 优化设备位置冲突检测和前端虚拟滚动

为设备表添加复合索引优化位置冲突检测性能
在设备位置检查中添加悲观锁防止竞态条件
添加 react-window 和 react-virtualized-auto-sizer 支持虚拟滚动
This commit is contained in:
zhangbing
2026-03-29 10:40:33 +08:00
parent 1d815b812e
commit 5d972799f2
6 changed files with 80 additions and 0 deletions
+3
View File
@@ -103,6 +103,9 @@ const Device = sequelize.define(
{ fields: ['createdAt'] },
{ fields: ['status', 'type'] },
{ fields: ['name'] },
// 优化位置冲突检测的复合索引
{ fields: ['rackId', 'position'] },
{ fields: ['rackId', 'position', 'isIdle'] },
],
}
);
+4
View File
@@ -63,6 +63,8 @@ async function checkPositionAvailable(
if (transaction) {
queryOptions.transaction = transaction;
// 使用悲观锁防止竞态条件
queryOptions.lock = transaction.LOCK ? transaction.LOCK.UPDATE : 'UPDATE';
}
const existingDevices = await Device.findAll(queryOptions);
@@ -126,6 +128,8 @@ async function checkBatchPositions(rackId, devices, excludeDeviceIds = [], trans
if (transaction) {
queryOptions.transaction = transaction;
// 使用悲观锁防止竞态条件
queryOptions.lock = transaction.LOCK ? transaction.LOCK.UPDATE : 'UPDATE';
}
const existingDevices = await Device.findAll(queryOptions);
+2
View File
@@ -1033,6 +1033,8 @@ async function checkPositionAvailable(
if (transaction) {
queryOptions.transaction = transaction;
// 使用悲观锁防止竞态条件
queryOptions.lock = transaction.LOCK ? transaction.LOCK.UPDATE : 'UPDATE';
}
const existingDevices = await Device.findAll(queryOptions);
+47
View File
@@ -95,6 +95,11 @@ const migrations = [
description: '为 deviceFields 表添加 isSystem 字段,标记系统字段不可删除',
migrate: migrateDeviceFieldsIsSystem,
},
{
name: '设备位置索引优化',
description: '为 devices 表添加复合索引,优化位置冲突检测和悲观锁性能',
migrate: migrateDevicePositionIndexes,
},
];
async function runMigrations() {
@@ -724,6 +729,48 @@ async function migrateIdleDeviceAndBusiness() {
}
}
async function migrateDevicePositionIndexes() {
const dialect = sequelize.getDialect();
const tableName = 'devices';
if (!(await tableExists(tableName))) {
console.log(` ${tableName} 表不存在,跳过`);
return;
}
console.log(` → 为 ${tableName} 表添加复合索引 rackId_position...`);
try {
if (dialect === 'sqlite') {
await sequelize.query(`CREATE INDEX IF NOT EXISTS devices_rackId_position ON ${tableName}(rackId, position)`);
} else {
await sequelize.query(`CREATE INDEX IF NOT EXISTS \`devices_rackId_position\` ON \`${tableName}\`(\`rackId\`, \`position\`)`);
}
console.log(' ✓ 索引创建成功');
} catch (error) {
if (error.message.includes('already exists') || error.message.includes('Duplicate key name')) {
console.log(' → 索引已存在,跳过');
} else {
throw error;
}
}
console.log(` → 为 ${tableName} 表添加复合索引 rackId_position_isIdle...`);
try {
if (dialect === 'sqlite') {
await sequelize.query(`CREATE INDEX IF NOT EXISTS devices_rackId_position_isIdle ON ${tableName}(rackId, position, isIdle)`);
} else {
await sequelize.query(`CREATE INDEX IF NOT EXISTS \`devices_rackId_position_isIdle\` ON \`${tableName}\`(\`rackId\`, \`position\`, \`isIdle\`)`);
}
console.log(' ✓ 索引创建成功');
} catch (error) {
if (error.message.includes('already exists') || error.message.includes('Duplicate key name')) {
console.log(' → 索引已存在,跳过');
} else {
throw error;
}
}
}
// 执行迁移
runMigrations().catch(error => {
console.error('迁移执行失败:', error);