一、HarmonyOS 数据持久化概述

在移动应用开发中,数据持久化是核心需求之一。HarmonyOS 5 提供了多种数据持久化方案,其中关系型数据库因其强大的结构化数据管理能力,成为处理复杂数据的首选方案。

HarmonyOS 5 的关系型数据库基于 SQLite 引擎构建,具有以下特点:

  1. ACID 事务支持:保证数据操作的原子性、一致性、隔离性和持久性
  2. 丰富的查询功能:支持标准 SQL 语法和复杂查询
  3. 跨设备同步:结合分布式能力实现多设备数据一致性
  4. 高性能:针对移动设备优化的存储引擎

二、关系型数据库核心概念

2.1 基本组件

  • RdbStore:数据库实例,提供增删改查接口
  • **谓词(Predicates)**:定义数据操作条件
  • **结果集(ResultSet)**:查询结果的集合
  • Schema:数据库表结构定义

2.2 运作机制

HarmonyOS 关系型数据库采用分层架构:

应用层 → 关系型数据库API → SQLite引擎 → 存储文件

这种设计既保持了SQLite的高效,又提供了面向对象的接口。

三、完整开发示例:学生成绩管理系统

下面我们通过一个完整的学生成绩管理案例,演示如何使用关系型数据库。

3.1 创建数据库和表

首先定义学生表结构,包含学号、姓名和各科成绩:

// 导入关系型数据库模块
import { relationalStore } from '@kit.ArkData';
import { BusinessError } from '@kit.BasicServicesKit';

// 定义学生表结构
const STUDENT_SCHEMA = {
  tableName: 'student',
  columns: {
    id: { // 学号为主键
      name: 'id',
      type: relationalStore.StoreType.INTEGER,
      isPrimaryKey: true
    },
    name: {
      name: 'name',
      type: relationalStore.StoreType.STRING,
      notNull: true
    },
    math: {
      name: 'math',
      type: relationalStore.StoreType.INTEGER,
      defaultValue: 0
    },
    english: {
      name: 'english', 
      type: relationalStore.StoreType.INTEGER,
      defaultValue: 0
    },
    science: {
      name: 'science',
      type: relationalStore.StoreType.INTEGER,
      defaultValue: 0
    }
  }
};

// 数据库配置
const config = {
  name: 'grades.db', // 数据库文件名
  securityLevel: relationalStore.SecurityLevel.S1 // 安全级别
};

// 创建或打开数据库
let rdbStore: relationalStore.RdbStore;
try {
  relationalStore.getRdbStore(this.context, config, (err, store) => {
    if (err) {
      console.error(`Failed to get RdbStore. Code:${err.code},message:${err.message}`);
      return;
    }
    console.info('Succeeded in getting RdbStore.');
    rdbStore = store;
    
    // 创建学生表
    rdbStore.createTable(STUDENT_SCHEMA.tableName, STUDENT_SCHEMA.columns, (err) => {
      if (err) {
        console.error(`Failed to create table. Code:${err.code},message:${err.message}`);
        return;
      }
      console.info('Succeeded in creating table.');
    });
  });
} catch (err) {
  const error = err as BusinessError;
  console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
}

3.2 插入学生数据

添加几个学生记录到数据库:

// 插入单个学生记录
const insertStudent = (student: {
  id: number,
  name: string,
  math: number,
  english: number,
  science: number
}) => {
  const valueBucket = {
    'id': student.id,
    'name': student.name,
    'math': student.math,
    'english': student.english,
    'science': student.science
  };
  
  rdbStore.insert(STUDENT_SCHEMA.tableName, valueBucket, (err, rowId) => {
    if (err) {
      console.error(`Failed to insert data. Code:${err.code},message:${err.message}`);
      return;
    }
    console.info(`Succeeded in inserting data. rowId:${rowId}`);
  });
}

// 批量插入示例数据
const students = [
  {id: 1001, name: '张三', math: 85, english: 92, science: 78},
  {id: 1002, name: '李四', math: 76, english: 88, science: 90},
  {id: 1003, name: '王五', math: 92, english: 79, science: 85}
];

students.forEach(student => {
  insertStudent(student);
});

3.3 查询学生成绩

实现按条件查询和排序功能:

// 查询所有学生并按总分降序排列
const queryAllStudents = () => {
  const columns = ['id', 'name', 'math', 'english', 'science'];
  const predicates = new relationalStore.RdbPredicates(STUDENT_SCHEMA.tableName);
  predicates.orderByDesc('(math + english + science)'); // 按总分降序
  
  rdbStore.query(predicates, columns, (err, resultSet) => {
    if (err) {
      console.error(`Failed to query data. Code:${err.code},message:${err.message}`);
      return;
    }
    
    console.info('学生成绩排名:');
    while (resultSet.goToNextRow()) {
      const id = resultSet.getDouble(resultSet.getColumnIndex('id'));
      const name = resultSet.getString(resultSet.getColumnIndex('name'));
      const math = resultSet.getDouble(resultSet.getColumnIndex('math'));
      const english = resultSet.getDouble(resultSet.getColumnIndex('english'));
      const science = resultSet.getDouble(resultSet.getColumnIndex('science'));
      const total = math + english + science;
      
      console.info(`学号:${id} 姓名:${name} 数学:${math} 英语:${english} 科学:${science} 总分:${total}`);
    }
    resultSet.close(); // 关闭结果集
  });
}

// 查询数学成绩大于80分的学生
const queryGoodAtMath = () => {
  const columns = ['id', 'name', 'math'];
  const predicates = new relationalStore.RdbPredicates(STUDENT_SCHEMA.tableName);
  predicates.greaterThan('math', 80); // 数学>80
  
  rdbStore.query(predicates, columns, (err, resultSet) => {
    if (err) {
      console.error(`Failed to query data. Code:${err.code},message:${err.message}`);
      return;
    }
    
    console.info('数学优秀学生:');
    while (resultSet.goToNextRow()) {
      const id = resultSet.getDouble(resultSet.getColumnIndex('id'));
      const name = resultSet.getString(resultSet.getColumnIndex('name'));
      const math = resultSet.getDouble(resultSet.getColumnIndex('math'));
      
      console.info(`学号:${id} 姓名:${name} 数学:${math}`);
    }
    resultSet.close();
  });
}

3.4 更新和删除数据

实现成绩修改和学生记录删除功能:

// 更新学生成绩
const updateStudentGrade = (studentId: number, subject: string, newGrade: number) => {
  const predicates = new relationalStore.RdbPredicates(STUDENT_SCHEMA.tableName);
  predicates.equalTo('id', studentId);
  
  const values = {
    [subject]: newGrade
  };
  
  rdbStore.update(values, predicates, (err, rowsAffected) => {
    if (err) {
      console.error(`Failed to update data. Code:${err.code},message:${err.message}`);
      return;
    }
    console.info(`Succeeded in updating data. rowsAffected:${rowsAffected}`);
  });
}

// 删除学生记录
const deleteStudent = (studentId: number) => {
  const predicates = new relationalStore.RdbPredicates(STUDENT_SCHEMA.tableName);
  predicates.equalTo('id', studentId);
  
  rdbStore.delete(predicates, (err, rowsAffected) => {
    if (err) {
      console.error(`Failed to delete data. Code:${err.code},message:${err.message}`);
      return;
    }
    console.info(`Succeeded in deleting data. rowsAffected:${rowsAffected}`);
  });
}

四、完整UI实现

下面我们将数据库操作与ArkUI结合,创建一个完整的学生成绩管理界面。

@Entry
@Component
struct StudentManager {
  @State students: Array<{
    id: number,
    name: string,
    math: number,
    english: number,
    science: number,
    total: number
  }> = [];

  // 加载学生数据
  loadStudents() {
    const columns = ['id', 'name', 'math', 'english', 'science'];
    const predicates = new relationalStore.RdbPredicates(STUDENT_SCHEMA.tableName);
    predicates.orderByDesc('(math + english + science)');
    
    rdbStore.query(predicates, columns, (err, resultSet) => {
      if (err) {
        console.error(`Failed to query data. Code:${err.code},message:${err.message}`);
        return;
      }
      
      this.students = [];
      while (resultSet.goToNextRow()) {
        const id = resultSet.getDouble(resultSet.getColumnIndex('id'));
        const name = resultSet.getString(resultSet.getColumnIndex('name'));
        const math = resultSet.getDouble(resultSet.getColumnIndex('math'));
        const english = resultSet.getDouble(resultSet.getColumnIndex('english'));
        const science = resultSet.getDouble(resultSet.getColumnIndex('science'));
        
        this.students.push({
          id,
          name,
          math,
          english,
          science,
          total: math + english + science
        });
      }
      resultSet.close();
    });
  }

  build() {
    Column() {
      // 标题
      Text('学生成绩管理系统')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 20 });

      // 刷新按钮
      Button('刷新数据')
        .onClick(() => {
          this.loadStudents();
        })
        .width('90%')
        .margin({ bottom: 20 });

      // 学生列表
      List({ space: 10 }) {
        ForEach(this.students, (student) => {
          ListItem() {
            Column() {
              Row() {
                Text(`学号: ${student.id}`)
                  .fontSize(16)
                  .fontWeight(FontWeight.Bold);
                
                Text(student.name)
                  .fontSize(16)
                  .margin({ left: 20 });
              }
              .width('100%')
              .justifyContent(FlexAlign.Start);

              Row() {
                Text(`数学: ${student.math}`)
                  .fontColor(Color.Red);
                Text(`英语: ${student.english}`)
                  .fontColor(Color.Blue)
                  .margin({ left: 10 });
                Text(`科学: ${student.science}`)
                  .fontColor(Color.Green)
                  .margin({ left: 10 });
                Text(`总分: ${student.total}`)
                  .fontWeight(FontWeight.Bold)
                  .margin({ left: 10 });
              }
              .width('100%')
              .margin({ top: 5 });
            }
            .padding(10)
            .width('100%')
            .borderRadius(10)
            .backgroundColor('#f5f5f5')
          }
        }, student => student.id.toString())
      }
      .width('100%')
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .padding(10)
    .onAppear(() => {
      this.loadStudents(); // 页面显示时加载数据
    })
  }
}

五、高级特性与最佳实践

5.1 事务处理

对于需要原子性的一组操作,使用事务保证数据一致性:

const transferScores = (fromId: number, toId: number, points: number) => {
  rdbStore.beginTransaction();
  
  try {
    // 减少源学生分数
    const deductPredicates = new relationalStore.RdbPredicates(STUDENT_SCHEMA.tableName);
    deductPredicates.equalTo('id', fromId);
    
    const deductValues = {
      'math': relationalStore.RdbStore.getSql('math - ?', [points])
    };
    
    rdbStore.update(deductValues, deductPredicates);
    
    // 增加目标学生分数
    const addPredicates = new relationalStore.RdbPredicates(STUDENT_SCHEMA.tableName);
    addPredicates.equalTo('id', toId);
    
    const addValues = {
      'math': relationalStore.RdbStore.getSql('math + ?', [points])
    };
    
    rdbStore.update(addValues, addPredicates);
    
    rdbStore.commit(); // 提交事务
    console.info('分数转移成功');
  } catch (err) {
    rdbStore.rollback(); // 回滚事务
    const error = err as BusinessError;
    console.error(`分数转移失败. Code:${error.code},message:${error.message}`);
  }
}

5.2 数据库升级

当需要修改表结构时,通过版本升级实现:

const upgradeDatabase = (context: Context) => {
  const config = {
    name: 'grades.db',
    securityLevel: relationalStore.SecurityLevel.S1,
    version: 2, // 新版本号
    onUpgrade: (store, oldVersion, newVersion) => {
      // 从版本1升级到版本2:添加历史成绩表
      if (oldVersion === 1 && newVersion === 2) {
        const HISTORY_SCHEMA = {
          tableName: 'history_scores',
          columns: {
            id: {
              name: 'id',
              type: relationalStore.StoreType.INTEGER,
              isPrimaryKey: true
            },
            student_id: {
              name: 'student_id',
              type: relationalStore.StoreType.INTEGER,
              notNull: true
            },
            exam_date: {
              name: 'exam_date',
              type: relationalStore.StoreType.STRING
            },
            scores: {
              name: 'scores',
              type: relationalStore.StoreType.STRING // JSON格式存储各科成绩
            }
          }
        };
        
        store.createTable(HISTORY_SCHEMA.tableName, HISTORY_SCHEMA.columns);
      }
    }
  };
  
  relationalStore.getRdbStore(context, config, (err, store) => {
    if (err) {
      console.error(`Failed to upgrade database. Code:${err.code},message:${err.message}`);
      return;
    }
    console.info('Database upgraded successfully');
  });
}

5.3 性能优化建议

  1. 批量操作:使用 executeBatch 进行批量插入/更新
  2. 索引优化:为常用查询条件创建索引
  3. 合理分页:大数据量查询使用 limitoffset
  4. 异步处理:耗时操作放在 TaskPool 中执行

六、总结

本文详细介绍了如何在 HarmonyOS 5 中使用关系型数据库实现数据持久化,从基本概念到完整实现,涵盖了:

  1. 数据库创建和表结构设计
  2. 增删改查等基本操作
  3. 事务处理和数据库升级
  4. 与ArkUI框架的集成
  5. 性能优化最佳实践

关系型数据库是HarmonyOS应用开发中处理结构化数据的强大工具,掌握这些技能将帮助你构建更健壮、高效的应用程序。随着HarmonyOS生态的发展,关系型数据库在多设备协同、数据安全等方面还将提供更多高级特性,值得开发者持续关注和学习。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐