第55555555章 数据管理 本章要点 .关系数据库的使用 课程思政 5 .分布式数据服务 本章知识结构图(见图5-1) 图5- 1 本章知识结构图 第5章数据管理 本章示例(见图5-2) 图5- 2 本章示例图 一个较好的应用程序,应该能够为用户保存个性化的设置,能够保存用户的使用记 录,而这些都离不开数据的存储,Han1. rmoyOS 提供了关系数据库来存储信息。5.5节 将通过一个基于DataAbility的关系数据库操作案例详细讲解关系数据库的使用方式, 读者可以根据该案例再次开发出其他更为复杂的应用程序。 HarmonyOS 还为开发者提供了分布式数据服务,当开发者想在两台或几台设备上 共享同一数据时,就可以通过使用分布式数据服务来完成,2. 5.4节将通过一个分布式数 据服务案例详细讲解HarmonyOS 的分布式数据服务的使用方式。 5.关系数据库 1 5.1 关系数据库介绍 1. 关系数据库(RelationalDatabase,RDB)是指采用关系模型组织数据的数据库,是创 建在关系模型基础上的数据库,以行和列的形式存储数据,方便用户理解。关系数据库可 以理解为由二维表及其之间的关系组成的一个数据组织。 HarmonyOS 关系数据库基于SQLite组件实现,提供了一套完整的对本地数据库进 行管理的机制,对外提供了一系列的增加、删除、修改、查询接口,也可以直接运行开发者 输入的SQL 语句来满足复杂的场景需要。 179 鸿蒙应用开发教程 5.2 约束与限制 1. .数据库中连接池的最大数量是4个,用以管理用户的读写操作。 .为保证数据的准确性,数据库同一时间只能支持一个写操作。 5.3 关系数据库相关类 1. 为了操作和管理关系数据库,HarmonyOS为开发者提供了一些相关类,常用的有 DatabaseHelper、RdbOpenCalback、RdbStore、RdbPredicates、RawRdbPredicates、 ResultSet。 DatabaseHelper是HarmonyOS提供的管理数据库的工具类,主要用于关系数据库 的创建、打开和删除。DatabaseHelper类定义的常用操作方法如表5-1所示。 表5- 1 DatabaseHelper类定义的常用操作方法 方法描述 publicRdbStoregetRdbStore(StoreConfigconfig,intversion, RdbOpenCalbackopenCalback,ResultSetHookresultSetHook) 根据配置创建或打开数据库 publicbooleandeleteRdbStore(Stringname) 删除指定的数据库 RdbOpenCalback是HarmonyOS为开发者提供的管理数据库创建、升级和降级的 工具类。开发者可以创建一个子类来实现onCreate()和onUpgrade()等方法,如果一个 数据库已经存在,它将被打开;如果不存在数据库,将创建一个新数据库。在数据库升级 过程中,也会调用此类的方法。RdbOpenCalback类定义的常用操作方法如表5-2所示。 表5- 2 RdbOpenCalback类定义的常用操作方法 方法描述 publicabstractvoidonCreate(RdbStorestore) publicabstractvoidonUpgrade(RdbStorestore,int curentVersion,inttargetVersion) 数据库创建时被调用,开发者可以在该方法中初 始化表结构,并添加一些应用使用到的初始化数据 数据库需要升级时被回调 voidonOpen(RdbStorestore) 打开数据库时调用 RdbStore是HarmonyOS提供的用来对关系数据库进行增加、删除、修改、查询操作 的工具类。RdbStore类定义的常用操作方法如表5-3所示。 表5- 3 RdbStore类定义的常用操作方法 方法描述 longinsert(Stringtable,ValuesBucketinitialValues) 向数据库插入数据 intupdate(ValuesBucketvalues,AbsRdbPredicatespredicates) 更新数据库表中符合谓词指定条 件的数据 ResultSetquery(AbsRdbPredicatespredicates,String[]columns) 查询数据 180 第5章数据管理 续表 方法描述 ResultSetquerySql(Stringsql,String[]sqlArgs) 执行原生的用于查询操作的SQL 语句 intdelete(AbsRdbPredicatespredicates) 删除数据 voidexecuteSql(StringsqlString) 执行原生的SQL语句 AbsRdbPredicates是关系数据库提供的用于设置数据库操作条件的谓词,其中包括 两个实现子类RdbPredicates和RawRdbPredicates。 .RdbPredicates:开发者无须编写复杂的SQL语句,仅通过调用该类中条件相关 的方法,如equalTo ()、notEqualTo ()、groupBy()、orderByAsc()、beginsWith() 等,就可自动完成SQL语句拼接,方便用户聚焦业务操作。 .RawRdbPredicates:可满足复杂SQL语句的场景,支持开发者自己设置where 条件子句和whereArgs参数,不支持equalTo等条件接口的使用。 RdbPredicates类定义的常用操作方法如表5-4所示。RawRdbPredicates类定义的 常用操作方法如表5-5所示。 表5- 4 RdbPredicates类定义的常用操作方法 方法描述 RdbPredicatesequalTo(Stringfield,Stringvalue) 设置谓词条件,满足field字段与value值相等 RdbPredicatesnotEqualTo(Stringfield,Stringvalue) 设置谓词条件,满足field字段与value值不 相等 RdbPredicatesbeginsWith(Stringfield,Stringvalue) 设置谓词条件,满足field字段以value值开头 RdbPredicatesbetwen(Stringfield,intlow,inthigh)设置谓词条件,满足field字段在最小值low 和最大值high之间 RdbPredicatesnotBetwen(Stringfield,intlow,int high) 设置谓词条件,满足field字段不在最小值low 和最大值high之间 RdbPredicatesorderByAsc(Stringfield) 设置谓词条件,根据field字段升序排列 RdbPredicatesorderByDesc(Stringfield) 设置谓词条件,根据field字段降序排列 RdbPredicatesgreaterThan(Stringfield,Stringvalue) 设置谓词条件,满足field字段比value值大 RdbPredicateslesThan(Stringfield,Stringvalue) 设置谓词条件,满足field字段比value值小 表5- 5 RawRdbPredicates类定义的常用操作方法 方法描述 voidsetWhereClause(StringwhereClause) 设置where条件子句 voidsetWhereArgs(List<String>whereArgs) 设置whereArgs参数,该值表示where子句中占位 符的值 ResultSet是关系数据库提供查询返回的结果集,它指向查询结果中的一行数据,供 181 鸿蒙应用开发教程 1 82 用户对查询结果进行遍历和访问。ResultSet类定义的常用操作方法如表5-6所示。 表5-6 ResultSet类定义的常用操作方法 方 法描 述 booleangoTo(intoffset) 从结果集当前位置移动指定偏移量 booleangoToRow(intposition) 将结果集移动到指定位置 booleangoToFirstRow() 将结果集移动到第一行 booleangoToLastRow() 将结果集移动到最后一行 booleangoToNextRow() 将结果集向后移动一行 booleangoToPreviousRow() 将结果集向前移动一行 booleanisStarted() 判断结果集是否被移动过 booleanisEnded() 判断结果集当前位置是否在最后一行之后 booleanisAtFirstRow() 判断结果集当前位置是否在第一行 booleanisAtLastRow() 判断结果集当前位置是否在最后一行 intgetRowCount() 获取当前结果集中的记录条数 intgetColumnCount() 获取结果集中的列数 StringgetString(intcolumnIndex) 获取当前行指定列的值,以String类型返回 intgetInt(inti) 获取当前行指定列的值,以int类型返回 voidclose() 关闭结果集 intgetColumnIndexForName(Strings) 获取结果集中列表名为s的列号 StringgetColumnNameForIndex(inti) 获取结果集中列号为i的列表名 5.1.4 关系数据库开发步骤 下面讲解关系数据库的创建,以及数据的增加、删除、修改、查询等基本步骤。 (1)首先创建数据库,配置数据库的相关信息,初始化数据库的表结构和相关数据, 示例代码如程序清单5-1所示。 程序清单5-1:hmos\ch05\01\RelationalDatabaseTest\entry\src\main\java\com\ example\relationaldatabasetest\slice\MainAbilitySlice.java 1 StoreConfig storeConfig = StoreConfig.newDefaultConfig("RdbStoreTest.db"); 2 DatabaseHelper databaseHelper= new DatabaseHelper(context); 3 private static RdbOpenCallback rdbOpenCallback = new RdbOpenCallback() { 4 @Override 5 public void onCreate(RdbStore rdbStore) { 6 //创建表 第5章 数据管理 1 83 7 rdbStore.executeSql("CREATE TABLE IF NOT EXISTS testdb (userId INTEGER PRIMARY KEY AUTOINCREMENT, userName TEXT NOT NULL, userAge INTEGER)"); 8 } 9 @Override 10 public void onUpgrade(RdbStore rdbStore, int oldVersion, int newVersion) { 11 //升级数据库操作 12 } 13 }; 14 RdbStore rdbStore = databaseHelper.getRdbStore(storeConfig, 1, rdbOpenCallback, null); (2)插入数据操作,以ValuesBucket形式构造要插入的数据,示例代码如程序清 单5-2所示。 程序清单5-2:hmos\ch05\01\RelationalDatabaseTest\entry\src\main\java\ com\example\relationaldatabasetest\slice\MainAbilitySlice.java 1 ValuesBucket values = new ValuesBucket(); 2 values.putInteger("userId", 1); 3 values.putString("userName", "Jerry"); 4 values.putInteger("userAge", 18); 5 long id = rdbStore.insert("User", values); 6 //使用SQL 语句插入数据 7 rdbStore.executeSql("insert into User (userId,userName,userAge) values (2,'Tom',20)"); (3)删除数据操作,详细代码如程序清单5-3所示。 程序清单5-3:hmos\ch05\01\RelationalDatabaseTest\entry\src\main\java\ com\example\relationaldatabasetest\slice\MainAbilitySlice.java 1 RdbPredicates rdbPredicates = new RdbPredicates("User").equalTo ("userName","Jerry"); 2 int i = rdbStore.delete(rdbPredicates); (4)查询数据操作,详细代码如程序清单5-4所示。 程序清单5-4:hmos\ch05\01\RelationalDatabaseTest\entry\src\main\java\ com\example\relationaldatabasetest\slice\MainAbilitySlice.java 1 //按条件查询 2 String[] columns = new String[] {"userId", "userName", "userAge"}; 鸿蒙应用开发教程 1 84 3 RdbPredicates rdbPredicates = new RdbPredicates("User").equalTo ("userAge", 18).orderByAsc("userId"); 4 ResultSet resultSet = store.query(rdbPredicates, columns); 5 resultSet.goToNextRow(); 6 //查询所有数据 7 String[] columns = new String[]{"userId","userName","userAge"}; 8 RdbPredicates rdbPredicates = new RdbPredicates("User");//构建查询谓词 9 ResultSet resultSet = rdbCreateDb().query(rdbPredicates,columns); 10 while (resultSet.goToNextRow()){ 11 int userId = resultSet.getInt(resultSet.getColumnIndexForName ("userId")); 12 String userName = resultSet.getString(resultSet. getColumnIndexForName("userName")); 13 int userAge = resultSet.getInt(resultSet.getColumnIndexForName ("userAge")); 14 } (5)更新数据操作,详细代码如程序清单5-5所示。 程序清单5-5:hmos\ch05\01\RelationalDatabaseTest\entry\src\main\java\ com\example\relationaldatabasetest\slice\MainAbilitySlice.java 1 RdbPredicates rdbPredicates = new RdbPredicates("User").equalTo ("userName","Tom"); 2 ValuesBucket values = new ValuesBucket(); 3 values.putString("userName","Lee"); 4 //更新数据 5 rdbStore.update(values,rdbPredicates); 5.1.5 基于DataAbility的关系数据库操作案例 前面讲解了操作HarmonyOS关系数据库的相关类以及关系数据库的基本开发步 骤。本节将实现基于DataAbility创建数据库服务,对外提供访问数据库的服务端接口 (PersonInfoDataAbility类),并在MainAbilitySlice中通过DataAbilityHelper与提供方 的DataAbility进行通信,最后通过日志查看数据库操作结果。 1.创建一个DataAbility 在新建的名为RelationalDatabaseTest的工程的主目录下添加一个名为dataability 的包,在dataability下添加一个名为PersonInfoDataAbility的EmptyDataAbility,用于 存储人员信息数据库并提供接口。HUAWEIDevEcoStudio将会自动生成数据库的 CRUD(增加、删除、修改、查询)方法,详细代码如程序清单5-6所示。 第5章 数据管理 1 85 程序清单5-6:hmos\ch05\01\RelationalDatabaseTest\entry\src\main\java\com\ example\relationaldatabasetest\dataability\PersonInfoDataAbility.java 1 public class PersonInfoDataAbility extends Ability { 2 private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo"); 3 4 @Override 5 public void onStart(Intent intent) { 6 super.onStart(intent); 7 HiLog.info(LABEL_LOG, "PersonInfoDataAbility onStart"); 8 } 9 10 @Override 11 public ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates) { 12 return null; 13 } 14 15 @Override 16 public int insert(Uri uri, ValuesBucket value) { 17 HiLog.info(LABEL_LOG, "PersonInfoDataAbility insert"); 18 return 999; 19 } 20 21 @Override 22 public int delete(Uri uri, DataAbilityPredicates predicates) { 23 return 0; 24 } 25 26 @Override 27 public int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates) { 28 return 0; 29 } 30 } 同时,HUAWEIDevEcoStudio将自动在工程配置文件config.json中添加如程序清 单5-7所示的配置。 程序清单5-7:hmos\ch05\01\RelationalDatabaseTest\entry\src\main\config.json 1 { 2 "permissions": [ 鸿蒙应用开发教程 1 86 3 "com.example.relationaldatabasetest.DataAbilityShellProvider. PROVIDER" 4 ], 5 "name": "com.example.relationaldatabasetest.dataability. PersonInfoDataAbility", 6 "icon": "$media:icon", 7 "description": "empty provider", 8 "type": "data", 9 "uri": "dataability://com.example.relationaldatabasetest.dataability. PersonInfoDataAbility" 10 } 2.定义DataAbility数据库相关常量 为了方便后续操作,在PersonInfoDataAbility类中定义数据库的相关常量,包括数 据库的库名、表名、表字段名、数据库版本号等,详细代码如程序清单5-8所示。 程序清单5-8:hmos\ch05\01\RelationalDatabaseTest\entry\src\main\java\com\ example\relationaldatabasetest\dataability\PersonInfoDataAbility.java 1 public class PersonInfoDataAbility extends Ability { 2 ... 3 private static final String DB_NAME = "personinfodataability.db"; //数据库名 4 private static final String DB_TAB_NAME = "personinfo"; //表名 5 private static final String DB_COLUMN_PERSON_ID = "id"; 6 private static final String DB_COLUMN_NAME = "name"; 7 private static final String DB_COLUMN_GENDER = "gender"; 8 private static final String DB_COLUMN_AGE = "age"; 9 private static final int DB_VERSION = 1; 10 ... 11 } 3.创建关系数据库 在PersonInfoDataAbility类中定义RdbStore变量,并通过RdbOpenCallback创建 数据库personinfodataability.db及表personinfo,详细代码如程序清单5-9所示。 程序清单5-9:hmos\ch05\01\RelationalDatabaseTest\entry\src\main\java\com\ example\relationaldatabasetest\dataability\PersonInfoDataAbility.java 1 private StoreConfig config = StoreConfig.newDefaultConfig(DB_NAME); 2 private RdbStore rdbStore; 3 private RdbOpenCallback rdbOpenCallback = new RdbOpenCallback() { 4 @Override 5 public void onCreate(RdbStore store) { 第5章 数据管理 1 87 6 store.executeSql("create table if not exists " 7 + DB_TAB_NAME + " (" 8 + DB_COLUMN_PERSON_ID + " integer primary key, " 9 + DB_COLUMN_NAME + " text not null, " 10 + DB_COLUMN_GENDER + " text not null, " 11 + DB_COLUMN_AGE + " integer)"); 12 } 13 14 @Override 15 public void onUpgrade(RdbStore store, int oldVersion, int newVersion) { 16 } 17 }; 4.初始化数据库连接 在程序应用启动时,系统会调用DataAbility中的onStart()方法创建Data实例。在 此方法中,需要创建数据库连接,并获取连接对象,以便后续对数据库进行操作,详细代码 如程序清单5-10所示。 程序清单5-10:hmos\ch05\01\RelationalDatabaseTest\entry\src\main\java\ com\example\relationaldatabasetest\dataability\PersonInfoDataAbility.java 1 @Override 2 public void onStart(Intent intent) { 3 super.onStart(intent); 4 HiLog.info(LABEL_LOG, "PersonInfoDataAbility onStart"); 5 DatabaseHelper databaseHelper = new DatabaseHelper(this); 6 rdbStore = databaseHelper.getRdbStore(config, DB_VERSION, rdbOpenCallback, null); 7 } 5.重写数据库操作方法 创建DataAbility时,HUAWEIDevEcoStudio自动生成数据库增加、删除、修改、查 询的空方法,开发者可以按照自身需要重写相关方法。 (1)query():查询数据方法。 该方法接收3 个参数,分别为uri(查询的目标路径)、columns(查询的列名)、 predicates(查询条件)。其中查询条件由DataAbilityPredicates类构建,详细代码如程序 清单5-11所示。 程序清单5-11:hmos\ch05\01\RelationalDatabaseTest\entry\src\main\java\com\ example\relationaldatabasetest\dataability\PersonInfoDataAbility.java 1 @Override