【鸿蒙开发】四、应用数据管理

ZJKJTL Android 开发  2021-08-07 00:06:22

 

 

        在鸿蒙中应用数据可以在本地单机存储,也支持分布式的跨设备相互同步的方式实现数据持久化。本地单机持久化有关系型数据库、对象关系映射数据库和轻量级偏好数据库。分布式持久化有分布式数据服务。下面进行详细介绍。

一、关系型数据库

        鸿蒙的关系型数据库是基于 SQLite 的,它运行所需的内存极小。鸿蒙提供的数据库功能更加完善,查询效率更高。对外提供了一系列的增、删、改、查接口,也可以直接运行SQL语句。

基本概念

  • 关系型数据库

    创建在关系模型基础上的数据库,以行和列的形式存储数据。

  • 谓词

    数据库中用来代表数据实体的性质、特征或者数据实体之间关系的词项,主要用来定义数据库的操作条件。

  • 结果集

    指用户查询之后的结果集合,可以对数据进行访问。结果集提供了灵活的数据访问方式,可以更方便的拿到用户想要的数据。

 

创建DataAbility

       关系型数据库的使用,首先创建一个 DataAbility 命名为 AppDatabaseDataAbility(创建方法之前的文章有写)。或者直接复制以下代码。

public class AppDatabaseDataAbility extends Ability {
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo");

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        HiLog.info(LABEL_LOG, "DatabaseDataAbility onStart");
    }

    @Override
    public ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates) {
        return null;
    }

    @Override
    public int insert(Uri uri, ValuesBucket value) {
        HiLog.info(LABEL_LOG, "DatabaseDataAbility insert");
        return 999;
    }

    @Override
    public int delete(Uri uri, DataAbilityPredicates predicates) {
        return 0;
    }

    @Override
    public int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates) {
        return 0;
    }

    @Override
    public FileDescriptor openFile(Uri uri, String mode) {
        return null;
    }

    @Override
    public String[] getFileTypes(Uri uri, String mimeTypeFilter) {
        return new String[0];
    }

    @Override
    public PacMap call(String method, String arg, PacMap extras) {
        return null;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }
}

如果是手动创建,需要将 DataAbility  添加到配置文件中。

"abilities": [
    "abilities": [
        {
            "permissions": [
                "com.example.helloharmony.db.DataAbilityShellProvider.PROVIDER"
            ],
            "name": "com.example.helloharmony.db.AppDatabaseDataAbility",
            "icon": "$media:icon",
            "description": "描述",
            "type": "data",
            "uri": "dataability://com.example.helloharmony.db.AppDatabaseDataAbility"
        }
    ]
]

配置数据库

假如我们现在需要创建一个商品信息表,其中包含GUID、商品名称、操作人员和商品数量。

private StoreConfig storeConfig = StoreConfig.newDefaultConfig("goodsinfo.db");

private RdbStore rdbStore;

private RdbOpenCallback rdbOpenCallback = new RdbOpenCallback() {
    @Override
    public void onCreate(RdbStore rdbStore) {
        // 数据库首次创建时调用
        rdbStore.executeSql("CREATE TABLE IF NOT EXISTS goods(" +
                "guid PRIMARY KEY," +
                "name TEXT NOT NULL," +
                "operator TEXT NOT NULL," +
                "number INTEGER)");
    }

    @Override
    public void onUpgrade(RdbStore rdbStore, int i, int i1) {
        // 数据库升级时调用(版本号变更时)
    }
};

onStart 函数中初始化数据库

@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    HiLog.info(LABEL_LOG, "DatabaseDataAbility onStart");

    // 创建一个数据库助手用于访问数据库
    DatabaseHelper databaseHelper = new DatabaseHelper(this);
    // 获取RDB存储
    rdbStore = databaseHelper.getRdbStore(storeConfig, 1, rdbOpenCallback, null);
}

重写数据操作方法 

 重写 DataAbility 框架的查询、新增、删除和更新方法以便操作数据库(可以自定义方法)

query() 方法

/**
 * 数据库查询
 *
 * @param uri        数据的数据库表
 * @param columns    要查询的列
 * @param predicates 过滤条件。如果该参数为空,则默认查询所有数据记录
 * @return 查询的数据
 */
@Override
public ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates) {
    RdbPredicates rdbPredicates = DataAbilityUtils.createRdbPredicates(predicates, "goods");

    return rdbStore.query(rdbPredicates, columns);
}

insert() 方法 

/**
 * 插入数据
 *
 * @param uri   数据的数据库表
 * @param value 要插入表中的数据行
 * @return 行ID
 */
@Override
public int insert(Uri uri, ValuesBucket value) {
    HiLog.info(LABEL_LOG, "AppDatabaseDataAbility insert");

    String path = uri.getLastPath();
    if ("goods".equals(path)) {
        ValuesBucket values = new ValuesBucket();
        values.putString("guid", value.getString("guid"));
        values.putString("name", value.getString("name"));
        values.putString("operator", value.getString("operator"));
        values.putInteger("number", value.getInteger("number"));

        // 行ID
        int index = (int) rdbStore.insert("goods", values);
        // 插入成功时知该表格数据的订阅者
        DataAbilityHelper.creator(this, uri).notifyChange(uri);
        return index;
    }

    HiLog.info(LABEL_LOG, "DataAbility insert path is not matched");
    return -1;
}

delete() 函数

/**
 * 删除数据
 *
 * @param uri        数据的数据库表
 * @param predicates 过滤条件。如果该参数为空,则默认查询所有数据记录
 * @return 受影响行ID
 */
@Override
public int delete(Uri uri, DataAbilityPredicates predicates) {
    RdbPredicates rdbPredicates = DataAbilityUtils.createRdbPredicates(predicates, "goods");
    // 受影响行ID
    int index = rdbStore.delete(rdbPredicates);
    // 删除成功时知该表格数据的订阅者
    DataAbilityHelper.creator(this, uri).notifyChange(uri);
    return index;
}

updata() 函数

/**
 * 更新数据
 *
 * @param uri        数据的数据库表
 * @param value      要插入表中的数据行
 * @param predicates 过滤条件。如果该参数为空,则默认查询所有数据记录
 * @return 受影响行ID
 */
@Override
public int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates) {
    RdbPredicates rdbPredicates = DataAbilityUtils.createRdbPredicates(predicates, "goods");
    int index = rdbStore.update(value, rdbPredicates);
    // 数据变更时知该表格数据的订阅者
    DataAbilityHelper.creator(this, uri).notifyChange(uri);
    return index;
}

关系数据库的使用

查询数据库

private void query() {
    String[] columns = new String[]{"guid", "name", "number"};
    // 构造查询条件,假如我们要查询商品为可乐的数量在0到200之间的操作有哪些?
    DataAbilityPredicates predicates = new DataAbilityPredicates();
    // 这部分的含义是商品名称为可乐的
    predicates.equalTo("name", "可乐");
    // 这部分的含义是商品数量在0到200之间的
    predicates.between("number", 0, 200);

    try {
        ResultSet resultSet = databaseHelper.query(
                    Uri.parse("dataability:///com.example.helloharmony.db.AppDatabaseDataAbility" + "/goods"),
                    columns,
                    predicates);

        while (resultSet.goToFirstRow()) {
            String name = resultSet.getString(resultSet.getColumnIndexForName("name"));
            String operator = resultSet.getString(resultSet.getColumnIndexForName("operator"));
            int number = resultSet.getInt(resultSet.getColumnIndexForName("number"));

            HiLog.info(LABEL_LOG, "商品:" + name + " 操作员:" + operator + " 数量:" + number);
        }
    } catch (DataAbilityRemoteException e) {
        e.printStackTrace();
    }
}

二、对象关系映射数据库 

        对象关系映射数据库是在 SQLite 上做了一层封装,屏蔽了底层数据库的SQL操作,提供一系列的面向对象接口,而不必再去编写复杂是SQL语句。

基本概念

  • 对象关系映射数据库的三个主要组件
    • 数据库:被开发者用@Database注解,且继承了OrmDatabase的类,对应关系型数据库。
    • 实体对象:被开发者用@Entity注解,且继承了OrmObject的类,对应关系型数据库中的表。
    • 对象数据操作接口:包括数据库操作的入口OrmContext类和谓词接口(OrmPredicate)等。
  • 谓词

    数据库中是用来代表数据实体的性质、特征或者数据实体之间关系的词项,主要用来定义数据库的操作条件。对象关系映射数据库将SQLite数据库中的谓词封装成了接口方法供开发者调用。开发者通过对象数据操作接口,可以访问到应用持久化的关系型数据。

  • 对象关系映射数据库

    通过将实例对象映射到关系上,实现使用操作实例对象的语法,来操作关系型数据库。它是在SQLite数据库的基础上提供的一个抽象层。

创建对象关系映射数据库

首先在配置“build.gradle”文件中添加下面的模块启动注解编译

ohos {
    ...
    compileOptions{
        annotationEnabled true
    }
    ...
}

我们还是以人员信息为例:

创建数据库实体Entity

@Entity(tableName = "person_info")
public class PersonEntity extends OrmObject {

    // 指定数据库主键
    @PrimaryKey
    private String guid;

    private String name;
    private String gender;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

创建构造数据库AppDatabase

配置数据库版本和实体

@Database(version = 1, entities = {PersonEntity.class})
public abstract class AppDatabase extends OrmDatabase {
}

 对象关系映射数据库的使用

初始化

// 数据库助手
DatabaseHelper databaseHelper = new DatabaseHelper(context);
/*
* 获取对象关系映射数据库上下文
* 参数分别为:ORM数据库别名、数据库文件、ORM数据库
*/
OrmContext ormContext = databaseHelper.getOrmContext("AppDatabase", "AppDatabase.db", AppDatabase.class);

 插入数据

/**
 * 插入数据
 *
 * @param personEntity 人员信息
 * @return 操作结果
 */
 private boolean insert(PersonEntity personEntity) {
    if (ormContext.insert(personEntity)) {
        return ormContext.flush();
    }

    return false;
 }

删除数据

/**
 * 删除数据
 *
 * @param personEntity 人员信息
 * @return 操作结果
 */
private boolean delete(PersonEntity personEntity) {
    if (ormContext.delete(personEntity)) {
        return ormContext.flush();
    }

    return false;
}

更新数据

/**
 * 更新数据
 *
 * @param personEntity 人员信息
 * @return 操作结果
 */
private boolean upData(PersonEntity personEntity) {
   if (ormContext.update(personEntity)) {
        return ormContext.flush();
    }

    return false;
}

三、轻量级偏好数据库

轻量级偏好数据库主要提供轻量级Key-Value操作,支持本地应用存储少量数据,数据存储在本地文件中,同时也加载在内存中的,所以访问速度更快,效率更高。轻量级偏好数据库属于非关系型数据库,不宜存储大量数据,经常用于操作键值对形式数据的场景。

基本概念

  • Key-Value数据库

    一种以键值对存储数据的一种数据库,类似Java中的map。Key是关键字,Value是值。

  • 非关系型数据库

    区别于关系数据库,不保证遵循ACID(Atomic、Consistency、Isolation及Durability)特性,不采用关系模型来组织数据,数据之间无关系,扩展性好。

  • 偏好数据

    用户经常访问和使用的数据。

 

 初始化

DatabaseHelper databaseHelper = new DatabaseHelper(context);
// 通过文件名称获取偏好数据库
Preferences preferences = databaseHelper.getPreferences("Setting");

读值

// 获取键为 intKey 的值,第二个参数是如果返回的值不是 int 型返回的值。
int value = preferences.getInt("intKey", 0);

 写值

preferences.putInt("intKey", 3);
// 同步
preferences.flushSync();

 

...全文
407 1 收藏 回复
写回复
回复
切换为时间正序
请发表友善的回复…
发表回复

还没有回复,快来抢沙发~

相关推荐
发帖
HarmonyOS技术社区
创建于2020-09-25

3187

社区成员

HarmonyOS是一款“面向未来”、面向全场景的分布式操作系统。在传统的单设备系统能力的基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持多种终端设备。
帖子事件
创建了帖子
2021-08-07 00:06
社区公告
鸿蒙技术社区致力成为开发者爱好者的交流学习平台,我们希望在这里提供鸿蒙代码实例、项目案例、并提供最新文档翻译。