HarmonyOS 鸿蒙Next中如何高效地进行批量数据操作?

HarmonyOS 鸿蒙Next中如何高效地进行批量数据操作? 1.在鸿蒙应用开发中,如何高效地进行批量数据操作? 2.批量插入、更新、删除数据时如何保证数据一致性?

3 回复

技术要点

  • 数据库事务(Transaction)
  • 批量插入优化
  • 错误回滚机制
  • 性能对比分析
  • 原子性保证

完整实现代码

/**
 * 批量操作示例 - DataService部分
 */

export class DataService {
  private dbManager: DatabaseManager;

  /**
   * 批量添加人物(使用事务)
   */
  public async batchAddPersons(persons: Person[]): Promise<string[]> {
    const store = this.dbManager.getStore();
    if (!store) throw new Error('数据库未初始化');

    const ids: string[] = [];
    const now = Date.now();

    try {
      // 1. 开启事务
      await store.beginTransaction();
      
      console.info(`开始批量添加${persons.length}个人物...`);
      
      // 2. 批量插入数据
      for (const person of persons) {
        const id = this.generateId();
        const insertSql = `
          INSERT INTO lelv_persons 
          (id, name, relationship_type, relationship_tags, phone, avatar, contact_id, create_time, update_time)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        `;

        await store.executeSql(insertSql, [
          id,
          person.name,
          person.relationshipType,
          JSON.stringify(person.relationshipTags),
          person.phone || null,
          person.avatar || null,
          person.contactId || null,
          now,
          now
        ]);
        
        ids.push(id);
      }
      
      // 3. 提交事务
      await store.commit();
      console.info(`批量添加人物成功: ${ids.length}个`);
      return ids;
    } catch (error) {
      // 4. 发生错误,回滚事务
      await store.rollback(void 0);
      console.error('批量添加人物失败:', JSON.stringify(error));
      throw new Error('批量添加人物失败');
    }
  }

  /**
   * 批量添加记录(使用事务)
   */
  public async batchAddRecords(records: HumanRecord[]): Promise<string[]> {
    const store = this.dbManager.getStore();
    if (!store) throw new Error('数据库未初始化');

    const ids: string[] = [];
    const now = Date.now();

    try {
      await store.beginTransaction();
      
      console.info(`开始批量添加${records.length}条记录...`);
      
      for (const record of records) {
        const id = this.generateId();
        const insertSql = `
          INSERT INTO lelv_human_records 
          (id, type, event_type, custom_event_type, amount, event_time, person_id, location, remark, photos, custom_fields, create_time, update_time)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        `;

        await store.executeSql(insertSql, [
          id,
          record.type,
          record.eventType,
          record.customEventType || null,
          record.amount,
          record.eventTime,
          record.personId,
          record.location || null,
          record.remark || null,
          JSON.stringify(record.photos || []),
          this.stringifyCustomFields(record.customFields),
          now,
          now
        ]);
        
        ids.push(id);
      }
      
      await store.commit();
      console.info(`批量添加记录成功: ${ids.length}条`);
      return ids;
    } catch (error) {
      await store.rollback(void 0);
      console.error('批量添加记录失败:', JSON.stringify(error));
      throw new Error('批量添加记录失败');
    }
  }

  /**
   * 批量删除人物(使用事务,级联删除记录)
   */
  public async batchDeletePersons(personIds: string[]): Promise<void> {
    const store = this.dbManager.getStore();
    if (!store) throw new Error('数据库未初始化');

    try {
      await store.beginTransaction();
      
      console.info(`开始批量删除${personIds.length}个人物...`);
      
      for (const personId of personIds) {
        // 先删除相关的人情记录
        await store.executeSql('DELETE FROM lelv_human_records WHERE person_id = ?', [personId]);
        // 再删除人物
        await store.executeSql('DELETE FROM lelv_persons WHERE id = ?', [personId]);
      }
      
      await store.commit();
      console.info(`批量删除人物成功: ${personIds.length}个`);
    } catch (error) {
      await store.rollback(void 0);
      console.error('批量删除人物失败:', JSON.stringify(error));
      throw new Error('批量删除人物失败');
    }
  }

  /**
   * 批量删除记录(使用事务)
   */
  public async batchDeleteRecords(recordIds: string[]): Promise<void> {
    const store = this.dbManager.getStore();
    if (!store) throw new Error('数据库未初始化');

    try {
      await store.beginTransaction();
      
      console.info(`开始批量删除${recordIds.length}条记录...`);
      
      for (const recordId of recordIds) {
        await store.executeSql('DELETE FROM lelv_human_records WHERE id = ?', [recordId]);
      }
      
      await store.commit();
      console.info(`批量删除记录成功: ${recordIds.length}条`);
    } catch (error) {
      await store.rollback(void 0);
      console.error('批量删除记录失败:', JSON.stringify(error));
      throw new Error('批量删除记录失败');
    }
  }

  /**
   * 批量更新记录(使用事务)
   */
  public async batchUpdateRecords(records: HumanRecord[]): Promise<void> {
    const store = this.dbManager.getStore();
    if (!store) throw new Error('数据库未初始化');

    try {
      await store.beginTransaction();
      
      console.info(`开始批量更新${records.length}条记录...`);
      
      for (const record of records) {
        const updateSql = `
          UPDATE lelv_human_records 
          SET type = ?, event_type = ?, amount = ?, event_time = ?, 
              location = ?, remark = ?, update_time = ?
          WHERE id = ?
        `;

        await store.executeSql(updateSql, [
          record.type,
          record.eventType,
          record.amount,
          record.eventTime,
          record.location || null,
          record.remark || null,
          Date.now(),
          record.id
        ]);
      }
      
      await store.commit();
      console.info(`批量更新记录成功: ${records.length}条`);
    } catch (error) {
      await store.rollback(void 0);
      console.error('批量更新记录失败:', JSON.stringify(error));
      throw new Error('批量更新记录失败');
    }
  }

  /**
   * 清空所有数据(使用事务)
   */
  public async clearAllData(): Promise<void> {
    const store = this.dbManager.getStore();
    if (!store) throw new Error('数据库未初始化');

    try {
      await store.beginTransaction();
      
      console.info('开始清空所有数据...');
      
      // 先删除记录
      await store.executeSql('DELETE FROM lelv_human_records');
      // 再删除人物
      await store.executeSql('DELETE FROM lelv_persons');
      // 重置设置
      await store.executeSql('DELETE FROM lelv_app_settings WHERE key NOT IN (?, ?)', 
        ['database_version', 'theme']);
      
      await store.commit();
      console.info('清空所有数据成功');
    } catch (error) {
      await store.rollback(void 0);
      console.error('清空数据失败:', JSON.stringify(error));
      throw new Error('清空数据失败');
    }
  }

  /**
   * 数据导入(使用事务,支持大批量)
   */
  public async importData(data: {persons: Person[], records: HumanRecord[]}): Promise<void> {
    const store = this.dbManager.getStore();
    if (!store) throw new Error('数据库未初始化');

    const now = Date.now();

    try {
      await store.beginTransaction();
      
      console.info(`开始导入数据: ${data.persons.length}个人物, ${data.records.length}条记录`);
      
      // 1. 导入人物
      for (const person of data.persons) {
        const insertSql = `
          INSERT OR REPLACE INTO lelv_persons 
          (id, name, relationship_type, relationship_tags, phone, avatar, contact_id, create_time, update_time)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        `;

        await store.executeSql(insertSql, [
          person.id,
          person.name,
          person.relationshipType,
          JSON.stringify(person.relationshipTags),
          person.phone || null,
          person.avatar || null,
          person.contactId || null,
          person.createTime || now,
          now
        ]);
      }
      
      // 2. 导入记录
      for (const record of data.records) {
        const insertSql = `
          INSERT OR REPLACE INTO lelv_human_records 
          (id, type, event_type, custom_event_type, amount, event_time, person_id, location, remark, photos, custom_fields, create_time, update_time)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        `;

        await store.executeSql(insertSql, [
          record.id,
          record.type,
          record.eventType,
          record.customEventType || null,
          record.amount,
          record.eventTime,
          record.personId,
          record.location || null,
          record.remark || null,
          JSON.stringify(record.photos || []),
          this.stringifyCustomFields(record.customFields),
          record.createTime || now,
          now
        ]);
      }
      
      await store.commit();
      console.info('数据导入成功');
    } catch (error) {
      await store.rollback(void 0);
      console.error('数据导入失败:', JSON.stringify(error));
      throw new Error('数据导入失败');
    }
  }
}

事务处理原理

1. 事务的四大特性(ACID)

  • 原子性(Atomicity): 事务中的所有操作要么全部成功,要么全部失败
  • 一致性(Consistency): 事务前后数据保持一致状态
  • 隔离性(Isolation): 多个事务并发执行互不干扰
  • 持久性(Durability): 事务提交后永久保存

2. 事务执行流程

try {
  await store.beginTransaction(); // 1. 开启事务
  // 2. 执行多个SQL操作
  await store.executeSql(sql1, params1);
  await store.executeSql(sql2, params2);
  await store.commit();           // 3. 提交事务
} catch (error) {
  await store.rollback(void 0);   // 4. 回滚事务
  throw error;
}

3. 回滚机制

当任何一条SQL执行失败时:

await store.rollback(void 0);  // 撤销所有操作

性能对比

逐条插入 vs 批量事务插入

// 方式1: 逐条插入(慢)
for (const person of persons) {
  await this.addPerson(person);  // 每次都提交
}
// 耗时: 1000条 ≈ 10秒

// 方式2: 批量事务插入(快)
await store.beginTransaction();
for (const person of persons) {
  await store.executeSql(sql, params);
}
await store.commit();  // 一次性提交
// 耗时: 1000条 ≈ 0.5秒

性能提升: 约20倍

使用示例

1. 批量导入数据

const persons: Person[] = [
  {id: '1', name: '张三', relationshipType: 'friend', ...},
  {id: '2', name: '李四', relationshipType: 'relative', ...},
  // ... 更多数据
];

const dataService = DataService.getInstance();
const ids = await dataService.batchAddPersons(persons);
console.info(`成功添加${ids.length}个人物`);

2. 批量删除数据

const personIds = ['1', '2', '3', '4', '5'];
await dataService.batchDeletePersons(personIds);

3. 数据完整导入

const backupData = {
  persons: [...],
  records: [...]
};

await dataService.importData(backupData);

最佳实践

1. 合理控制批量大小

// 分批处理,避免单次事务过大
const batchSize = 100;
for (let i = 0; i < persons.length; i += batchSize) {
  const batch = persons.slice(i, i + batchSize);
  await this.batchAddPersons(batch);
}

2. 错误处理要完整

try {
  await store.beginTransaction();
  // ... 操作
  await store.commit();
} catch (error) {
  await store.rollback(void 0);  // 必须回滚
  throw new Error(`操作失败: ${error.message}`);
}

3. 记录操作日志

console.info(`开始批量操作: ${records.length}条`);
await store.beginTransaction();
// ... 操作
await store.commit();
console.info(`批量操作成功`);

4. 使用INSERT OR REPLACE

// 避免主键冲突,支持更新
INSERT OR REPLACE INTO table_name VALUES (...)

避坑指南

1. ❌ 忘记回滚事务

// 错误示例
try {
  await store.beginTransaction();
  // ... 操作
  await store.commit();
} catch (error) {
  // 忘记回滚!
  throw error;
}

// 正确示例
try {
  await store.beginTransaction();
  // ... 操作
  await store.commit();
} catch (error) {
  await store.rollback(void 0);  // 必须回滚
  throw error;
}

2. ❌ 事务嵌套

// 不支持事务嵌套
await store.beginTransaction();
await store.beginTransaction();  // ❌ 错误

3. ❌ 事务中执行长时间操作

// 事务应尽快提交
await store.beginTransaction();
// ❌ 不要在事务中执行复杂计算或网络请求
await someComplexCalculation();
await store.commit();

4. ❌ 不检查返回值

// 应该检查操作结果
const result = await store.executeSql(sql, params);
if (result === undefined) {
  throw new Error('SQL执行失败');
}

性能优化建议

  1. 使用预编译语句: 相同SQL多次执行时复用
  2. 合理设置批量大小: 100-1000条为宜
  3. 避免频繁commit: 批量操作使用一个事务
  4. 建立合适索引: 加速查询和删除
  5. 定期VACUUM: 回收空间,优化性能

实际应用场景

  1. 数据导入: Excel导入大量记录
  2. 数据迁移: 版本升级时迁移数据
  3. 批量删除: 清理历史数据
  4. 数据同步: 云端同步大量数据
  5. 备份恢复: 恢复备份文件

总结

本文实现了完整的批量操作方案:

  • ✅ 事务保证数据一致性
  • ✅ 批量插入性能提升20倍
  • ✅ 完善的错误回滚机制
  • ✅ 支持大批量数据导入
  • ✅ 级联删除保证数据完整性

更多关于HarmonyOS 鸿蒙Next中如何高效地进行批量数据操作?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


HarmonyOS Next中批量数据操作可通过分布式数据管理框架实现。使用KVStore或关系型数据库的批量接口,如executeBatch()方法进行事务处理。结合DataShareExtensionAbility跨应用同步数据。利用ResultSet高效遍历查询结果,通过Predicates批量筛选。

在HarmonyOS Next中进行高效批量数据操作,推荐使用关系型数据库(RDB)的批处理能力。以下是关键方法:

  1. 使用RDB批处理接口

    • 通过RdbStore.executeSqlBatch()方法执行批量SQL操作,将多个操作封装在单次事务中,显著减少I/O开销。
    • 示例:
      const sqlBatch = [
        "INSERT INTO user (name, age) VALUES (?, ?)",
        "UPDATE user SET age = ? WHERE name = ?",
        "DELETE FROM user WHERE age < ?"
      ];
      const argsBatch = [
        ["张三", 25],
        [26, "张三"],
        [18]
      ];
      await rdbStore.executeSqlBatch(sqlBatch, argsBatch);
      
  2. 保证数据一致性

    • 批处理默认在事务中执行,所有操作要么全部成功,要么全部回滚,确保原子性。
    • 可结合beginTransaction()commit()rollback()手动控制事务边界,应对复杂逻辑。
  3. 性能优化建议

    • 批量操作前预编译SQL语句,避免重复解析。
    • 合理设置批处理大小(如每次100-500条),平衡内存与性能。
    • 对于超大数据集,考虑分批次处理并适时提交事务,避免内存压力。
  4. 使用对象关系映射(ORM)

    • 通过@ohos.data.relationalStore的ORM能力,批量操作对象实体,简化代码并保持性能。

这种方式直接利用数据库引擎的优化,是鸿蒙Next中处理批量数据的标准实践。

回到顶部