1# 通过关系型数据库实现数据持久化 (C/C++) 2<!--Kit: ArkData--> 3<!--Subsystem: DistributedDataManager--> 4<!--Owner: @baijidong--> 5<!--Designer: @widecode; @htt1997--> 6<!--Tester: @yippo; @logic42--> 7<!--Adviser: @ge-yafang--> 8 9## 场景介绍 10 11RelationalStore提供了一套完整的对本地数据库进行管理的机制,对外提供了一系列的增、删、改、查等接口,也可以直接运行用户输入的SQL语句来满足复杂的场景需要。 12 13 14## 基本概念 15 16- **谓词**:数据库中用来代表数据实体的性质、特征或者数据实体之间关系的词项,主要用来定义数据库的操作条件。 17 18- **结果集**:指用户查询之后的结果集合,可以对数据进行访问。结果集提供了灵活的数据访问方式,可以更方便地拿到用户想要的数据。 19 20 21## 约束限制 22 23- 系统默认日志方式是WAL(Write Ahead Log)模式,系统默认落盘方式是FULL模式。 24 25- 数据库中连接池的最大数量是4个,用以管理用户的读操作。 26 27- 为保证数据的准确性,数据库同一时间仅支持一个写操作。 28 29- 当应用被卸载完成后,设备上的相关数据库文件及临时文件会被自动清除。 30 31## 接口说明 32 33详细的接口说明请参考[RDB](../reference/apis-arkdata/capi-rdb.md)。 34 35| 接口名称 | 描述 | 36| -------- | -------- | 37 OH_Rdb_ConfigV2 *OH_Rdb_CreateConfig() | 创建一个OH_Rdb_ConfigV2实例,并返回指向该实例的指针。 | 38 int OH_Rdb_SetDatabaseDir(OH_Rdb_ConfigV2 *config, const char *databaseDir) | 给指定的数据库文件配置OH_Rdb_ConfigV2,设置数据库文件路径。 | 39 int OH_Rdb_SetStoreName(OH_Rdb_ConfigV2 *config, const char *storeName) | 给指定的数据库文件配置OH_Rdb_ConfigV2,设置数据库名称。 | 40 int OH_Rdb_SetBundleName(OH_Rdb_ConfigV2 *config, const char *bundleName) | 给指定的数据库文件配置OH_Rdb_ConfigV2,设置应用包名。 | 41 int OH_Rdb_SetModuleName(OH_Rdb_ConfigV2 *config, const char *moduleName) | 给指定的数据库文件配置OH_Rdb_ConfigV2,设置应用模块名。 | 42 int OH_Rdb_SetSecurityLevel(OH_Rdb_ConfigV2 *config, int securityLevel) | 给指定的数据库文件配置OH_Rdb_ConfigV2,设置数据库安全级别OH_Rdb_SecurityLevel。 | 43 int OH_Rdb_SetEncrypted(OH_Rdb_ConfigV2 *config, bool isEncrypted) | 给指定的数据库文件配置OH_Rdb_ConfigV2,设置数据库是否加密。 | 44 int OH_Rdb_SetArea(OH_Rdb_ConfigV2 *config, int area) | 给指定的数据库文件配置OH_Rdb_ConfigV2,设置数据库安全区域等级Rdb_SecurityArea。 | 45| OH_Rdb_Store *OH_Rdb_CreateOrOpen(const OH_Rdb_ConfigV2 *config, int *errCode) | 使用数据库配置OH_Rdb_ConfigV2,获得一个对应的OH_Rdb_Store实例,用来操作关系型数据库。 | 46| OH_Rdb_Execute(OH_Rdb_Store *store, const char *sql) | 执行包含指定参数但不返回值的SQL语句。 | 47| OH_Rdb_Insert(OH_Rdb_Store *store, const char *table, OH_VBucket *valuesBucket) | 向目标表中插入一行数据。 | 48| int OH_Rdb_InsertWithConflictResolution(OH_Rdb_Store *store, const char *table, OH_VBucket *row, Rdb_ConflictResolution resolution, int64_t *rowId) | 向目标表中插入一行数据,支持配置冲突解决策略。 | 49| int OH_Rdb_UpdateWithConflictResolution(OH_Rdb_Store *store, OH_VBucket *row, OH_Predicates *predicates, Rdb_ConflictResolution resolution, int64_t *changes) | 向目标表中插入一行数据,支持配置冲突解决策略。 | 50| OH_Rdb_Update(OH_Rdb_Store *store, OH_VBucket *valuesBucket, OH_Predicates *predicates) | 根据OH_Predicates的指定实例对象更新数据库中的数据。 | 51| OH_Rdb_Delete(OH_Rdb_Store *store, OH_Predicates *predicates) | 根据OH_Predicates的指定实例对象从数据库中删除数据。 | 52| int OH_Predicates_NotLike(OH_Predicates *predicates, const char *field, const char *pattern) | 设置OH_Predicates以匹配数据类型为字符串且值不类似于指定值的字段。 | 53| int OH_Predicates_Glob(OH_Predicates *predicates, const char *field, const char *pattern) | 设置OH_Predicates以匹配指定字段(数据类型为字符串)且值包含通配符的字段。 | 54| int OH_Predicates_NotGlob(OH_Predicates *predicates, const char *field, const char *pattern) | 设置OH_Predicates以不匹配指定字段(数据类型为字符串)且值包含通配符的字段。 | 55| OH_Rdb_Query(OH_Rdb_Store *store, OH_Predicates *predicates, const char *const *columnNames, int length) | 根据指定条件查询数据库中的数据。 | 56| OH_Rdb_DeleteStore(const OH_Rdb_Config *config) | 删除数据库。 | 57| OH_VBucket_PutAsset(OH_VBucket *bucket, const char *field, Rdb_Asset *value) | 把Rdb_Asset类型的数据放到指定的OH_VBucket对象中。 | 58| OH_VBucket_PutAssets(OH_VBucket *bucket, const char *field, Rdb_Asset *value, uint32_t count) | 把Rdb_Asset数组类型的数据放到指定的OH_VBucket对象中。 | 59| OH_Rdb_FindModifyTime(OH_Rdb_Store *store, const char *tableName, const char *columnName, OH_VObject *values) | 获取数据库指定表中指定列的数据的最后修改时间。 | 60| OH_RDB_TransOptions *OH_RdbTrans_CreateOptions(void) | 创建一个OH_RDB_TransOptions实例,配置事务对象。 | 61| OH_Cursor *OH_RdbTrans_Query(OH_Rdb_Transaction *trans, const OH_Predicates *predicates, const char *columns[], int len) | 根据指定的条件查询数据库中的数据。 | 62| OH_Data_Values *OH_Values_Create(void) | 创建OH_Data_Values实例。 | 63| int OH_Data_Asset_SetName(Data_Asset *asset, const char *name) | 为资产类型数据设置名称。 | 64| int OH_Data_Asset_SetUri(Data_Asset *asset, const char *uri) | 为资产类型数据设置绝对路径。 | 65| int OH_Data_Asset_SetPath(Data_Asset *asset, const char *path) | 为资产类型数据设置应用沙箱里的相对路径。 | 66| int OH_Data_Asset_SetCreateTime(Data_Asset *asset, int64_t createTime) | 为资产类型数据设置创建时间。 | 67| int OH_Data_Asset_SetModifyTime(Data_Asset *asset, int64_t modifyTime) | 为资产类型数据设置最后修改时间。 | 68| int OH_Data_Asset_SetSize(Data_Asset *asset, size_t size) | 为资产类型数据设置占用空间大小。 | 69| int OH_Data_Asset_SetStatus(Data_Asset *asset, Data_AssetStatus status) | 为资产类型数据设置状态码。 | 70| int OH_Data_Asset_GetName(Data_Asset *asset, char *name, size_t *length) | 获取资产类型数据的名称。 | 71| int OH_Data_Asset_GetUri(Data_Asset *asset, char *uri, size_t *length) | 获取资产类型数据的绝对路径。 | 72| int OH_Data_Asset_GetPath(Data_Asset *asset, char *path, size_t *length) | 获取资产类型数据在应用沙箱内的相对路径。 | 73| int OH_Data_Asset_GetCreateTime(Data_Asset *asset, int64_t *createTime) | 获取资产类型数据的创建时间。 | 74| int OH_Data_Asset_GetModifyTime(Data_Asset *asset, int64_t *modifyTime) | 获取资产类型数据的最后修改时间。 | 75| int OH_Data_Asset_GetSize(Data_Asset *asset, size_t *size) | 获取资产类型数据的占用空间大小。 | 76| int OH_Data_Asset_GetStatus(Data_Asset *asset, Data_AssetStatus *status) | 获取资产类型数据的状态码。 | 77| Data_Asset *OH_Data_Asset_CreateOne() | 创造一个资产类型实例。使用完毕后需要调用OH_Data_Asset_DestroyOne释放内存。 | 78| int OH_Data_Asset_DestroyOne(Data_Asset *asset) | 销毁一个资产类型实例并回收内存。 | 79| Data_Asset **OH_Data_Asset_CreateMultiple(uint32_t count) | 创造指定数量的资产类型实例。使用完毕后需要调用OH_Data_Asset_DestroyMultiple释放内存。 | 80| int OH_Data_Asset_DestroyMultiple(Data_Asset **assets, uint32_t count) | 销毁指定数量的资产类型实例并回收内存。 | 81| int OH_Rdb_CreateTransaction(OH_Rdb_Store *store, const OH_RDB_TransOptions *options, OH_Rdb_Transaction **trans) | 创建一个相关的OH_Rdb_Transaction实例,开启事务。 | 82| int OH_RdbTransOption_SetType(OH_RDB_TransOptions *options, OH_RDB_TransType type) | 设置事务对象类型。 | 83| int OH_RdbTrans_Insert(OH_Rdb_Transaction *trans, const char *table, const OH_VBucket *row, int64_t *rowId) | 向目标表中插入一行数据。 | 84| int OH_RdbTrans_InsertWithConflictResolution(OH_Rdb_Transaction *trans, const char *table, const OH_VBucket *row, Rdb_ConflictResolution resolution, int64_t *rowId) | 将一行数据插入到目标表中,支持冲突解决。 | 85| int OH_RdbTrans_UpdateWithConflictResolution(OH_Rdb_Transaction *trans, const OH_VBucket *row, const OH_Predicates *predicates, Rdb_ConflictResolution resolution, int64_t *changes) | 根据指定条件更新数据库中的数据,并支持冲突解决。 | 86| int OH_RdbTrans_Delete(OH_Rdb_Transaction *trans, const OH_Predicates *predicates, int64_t *changes) | 根据OH_Predicates的指定实例对象从数据库中删除数据。 | 87| int OH_Value_Destroy(OH_Data_Value *value) | 销毁OH_Data_Value对象。 | 88| int OH_Values_Destroy(OH_Data_Values *values) | 销毁OH_Values_Destroy对象。 | 89| int OH_RdbTrans_Execute(OH_Rdb_Transaction *trans, const char *sql, const OH_Data_Values *args, OH_Data_Value **result) | 执行包含指定参数的SQL语句。 | 90| int OH_RdbTrans_Commit(OH_Rdb_Transaction *trans) | 提交事务。 | 91| int OH_RdbTrans_Rollback(OH_Rdb_Transaction *trans) | 回滚事务。 | 92| int OH_RdbTrans_Destroy(OH_Rdb_Transaction *trans) | 销毁OH_Rdb_Transaction实例。 | 93| int OH_Rdb_Attach(OH_Rdb_Store *store, const OH_Rdb_ConfigV2 *config, const char *attachName, int64_t waitTime, size_t *attachedNumber) | 将数据库文件附加到当前连接的数据库。 | 94| int OH_Rdb_Detach(OH_Rdb_Store *store, const char *attachName, int64_t waitTime, size_t *attachedNumber) | 从当前数据库中分离指定的数据库。 | 95| int OH_Rdb_SetCustomDir(OH_Rdb_ConfigV2 *config, const char *customDir) | 设置数据库的自定义目录。 | 96| int OH_Rdb_SetLocale(OH_Rdb_Store *store, const char *locale) | 支持不同语言的排序规则。 | 97| int OH_Rdb_SetPlugins(OH_Rdb_ConfigV2 *config, const char **plugins, int32_t length) | 设置具有特定功能(如全文检索)的动态库。 | 98 99## 开发步骤 100 101**添加动态链接库** 102 103CMakeLists.txt中添加以下lib。 104 105```txt 106libnative_rdb_ndk.z.so 107``` 108 109**头文件** 110 111```c 112#include <database/data/data_asset.h> 113#include <database/rdb/oh_cursor.h> 114#include <database/rdb/oh_predicates.h> 115#include <database/rdb/oh_value_object.h> 116#include <database/rdb/oh_values_bucket.h> 117#include <database/rdb/relational_store.h> 118#include <database/rdb/relational_store_error_code.h> 119``` 120 1211. 获取OH_Rdb_Store实例,创建数据库文件。其中dataBaseDir变量为应用沙箱路径,Stage模式下建议使用数据库目录,参考[Context](../reference/apis-ability-kit/js-apis-inner-application-context.md)的databaseDir属性。FA模式下,由于没有接口获取数据库沙箱路径,可使用应用程序的文件目录,可参考[Context](../reference/apis-ability-kit/js-apis-inner-app-context.md)的getFilesDir接口。area为数据库文件存放的安全区域,详见[contextConstant](../reference/apis-ability-kit/js-apis-app-ability-contextConstant.md),开发时需要实现由AreaMode枚举值对Rdb_SecurityArea枚举值的转换。示例代码如下所示: 122 123 ```c 124 // 创建OH_Rdb_ConfigV2对象 125 OH_Rdb_ConfigV2* config = OH_Rdb_CreateConfig(); 126 // 该路径为应用沙箱路径 127 // 数据库文件创建位置将位于沙箱路径 /data/storage/el2/database/rdb/RdbTest.db 128 OH_Rdb_SetDatabaseDir(config, "/data/storage/el2/database"); 129 // 数据库文件名 130 OH_Rdb_SetStoreName(config, "RdbTest.db"); 131 // 应用包名 132 OH_Rdb_SetBundleName(config, "com.example.nativedemo"); 133 // 应用模块名 134 OH_Rdb_SetModuleName(config, "entry"); 135 // 数据库文件安全等级 136 OH_Rdb_SetSecurityLevel(config, OH_Rdb_SecurityLevel::S3); 137 // 数据库是否加密 138 OH_Rdb_SetEncrypted(config, false); 139 // 数据库文件存放的安全区域 140 OH_Rdb_SetArea(config, RDB_SECURITY_AREA_EL2); 141 142 int errCode = 0; 143 // 获取OH_Rdb_Store实例 144 OH_Rdb_Store *store_ = OH_Rdb_CreateOrOpen(config, &errCode); 145 ``` 146 147 ```c 148 // 可设置自定义数据库路径 149 // 数据库文件创建位置将位于沙箱路径 /data/storage/el2/database/a/b/RdbTest.db 150 OH_Rdb_SetCustomDir(config, "../a/b"); 151 // 可设置为只读模式打开数据库 152 OH_Rdb_SetReadOnly(config, true); 153 ``` 154 1552. 获取到OH_Rdb_Store后,调用OH_Rdb_Execute接口创建表,并调用OH_Rdb_Insert接口插入数据。示例代码如下所示: 156 157 ```c 158 char createTableSql[] = "CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, " 159 "AGE INTEGER, SALARY REAL, CODES BLOB)"; 160 // 执行建表语句 161 OH_Rdb_Execute(store_, createTableSql); 162 163 // 创建键值对实例 164 OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket(); 165 valueBucket->putText(valueBucket, "NAME", "Lisa"); 166 valueBucket->putInt64(valueBucket, "AGE", 18); 167 valueBucket->putReal(valueBucket, "SALARY", 100.5); 168 uint8_t arr[] = {1, 2, 3, 4, 5}; 169 int len = sizeof(arr) / sizeof(arr[0]); 170 valueBucket->putBlob(valueBucket, "CODES", arr, len); 171 // 插入数据 172 int rowId = OH_Rdb_Insert(store_, "EMPLOYEE", valueBucket); 173 174 OH_VBucket *valueBucket2 = OH_Rdb_CreateValuesBucket(); 175 valueBucket2->putInt64(valueBucket2, "ID", 1); 176 valueBucket2->putText(valueBucket2, "NAME", "zhangsan"); 177 valueBucket2->putInt64(valueBucket2, "AGE", 24); 178 valueBucket2->putReal(valueBucket2, "SALARY", 120.4); 179 int64_t rowId2 = -1; 180 // 支持插入数据时配置冲突策略 181 int result = OH_Rdb_InsertWithConflictResolution(store_, "EMPLOYEE", valueBucket2, 182 Rdb_ConflictResolution::RDB_CONFLICT_REPLACE, &rowId2); 183 // 销毁键值对实例 184 valueBucket->destroy(valueBucket); 185 valueBucket2->destroy(valueBucket2); 186 ``` 187 188 > **说明:** 189 > 190 > 关系型数据库没有显式的flush操作实现持久化,数据插入即保存在持久化文件。 191 1923. 根据谓词指定的实例对象,对数据进行修改或删除。 193 194 调用OH_Rdb_Update方法修改数据,调用OH_Rdb_Delete方法删除数据。示例代码如下所示: 195 196 ```c 197 // 修改数据 198 OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket(); 199 valueBucket->putText(valueBucket, "NAME", "Rose"); 200 valueBucket->putInt64(valueBucket, "AGE", 22); 201 valueBucket->putReal(valueBucket, "SALARY", 200.5); 202 uint8_t arr[] = {1, 2, 3, 4, 5}; 203 int len = sizeof(arr) / sizeof(arr[0]); 204 valueBucket->putBlob(valueBucket, "CODES", arr, len); 205 206 OH_Predicates *predicates = OH_Rdb_CreatePredicates("EMPLOYEE"); 207 OH_VObject *valueObject = OH_Rdb_CreateValueObject(); 208 const char *name = "Lisa"; 209 valueObject->putText(valueObject, name); 210 predicates->equalTo(predicates, "NAME", valueObject)->andOperate(predicates); 211 uint32_t count = 1; 212 double salary = 100.5; 213 valueObject->putDouble(valueObject, &salary, count); 214 predicates->equalTo(predicates, "SALARY", valueObject); 215 216 int changeRows = OH_Rdb_Update(store_, valueBucket, predicates); 217 int rowId = OH_Rdb_Insert(store_, "EMPLOYEE", valueBucket); 218 OH_Predicates *predicates2 = OH_Rdb_CreatePredicates("EMPLOYEE"); 219 OH_VObject *valueObject2 = OH_Rdb_CreateValueObject(); 220 valueObject2->putText(valueObject2, "Rose"); 221 predicates2->equalTo(predicates2, "NAME", valueObject2); 222 valueBucket->putInt64(valueBucket, "ID", 1); 223 valueBucket->putText(valueBucket, "NAME", "zhangsan"); 224 int64_t changeRows2 = -1; 225 226 // 支持更新数据时配置冲突策略 227 int result = OH_Rdb_UpdateWithConflictResolution(store_, valueBucket, predicates2, 228 Rdb_ConflictResolution::RDB_CONFLICT_REPLACE, &changeRows2); 229 valueObject->destroy(valueObject); 230 valueObject2->destroy(valueObject2); 231 valueBucket->destroy(valueBucket); 232 predicates->destroy(predicates); 233 predicates2->destroy(predicates2); 234 ``` 235 236 ```c 237 // 删除数据 238 OH_Predicates *predicates = OH_Rdb_CreatePredicates("EMPLOYEE"); 239 OH_VObject *valueObject = OH_Rdb_CreateValueObject(); 240 const char *name = "Lisa"; 241 valueObject->putText(valueObject, name); 242 predicates->equalTo(predicates, "NAME", valueObject); 243 int deleteRows = OH_Rdb_Delete(store_, predicates); 244 valueObject->destroy(valueObject); 245 predicates->destroy(predicates); 246 ``` 247 2484. 根据谓词指定的查询条件查找数据。 249 250 调用OH_Rdb_Query方法查找数据,返回一个OH_Cursor结果集。示例代码如下所示: 251 252 ```c 253 OH_Predicates *predicates = OH_Rdb_CreatePredicates("EMPLOYEE"); 254 255 const char *columnNames[] = {"NAME", "AGE"}; 256 int len = sizeof(columnNames) / sizeof(columnNames[0]); 257 OH_Cursor *cursor = OH_Rdb_Query(store_, predicates, columnNames, len); 258 259 int columnCount = 0; 260 cursor->getColumnCount(cursor, &columnCount); 261 262 // OH_Cursor是一个数据集合的游标,默认指向第-1个记录,有效的数据从0开始 263 int64_t age; 264 while (cursor->goToNextRow(cursor) == OH_Rdb_ErrCode::RDB_OK) { 265 int32_t ageColumnIndex = -1; 266 cursor->getColumnIndex(cursor, "AGE", &ageColumnIndex); 267 if (ageColumnIndex != -1) { 268 cursor->getInt64(cursor, ageColumnIndex, &age); 269 } 270 } 271 272 // 释放谓词实例 273 predicates->destroy(predicates); 274 // 释放结果集 275 cursor->destroy(cursor); 276 ``` 277 278 配置谓词以LIKE模式或NOTLIKE模式匹配进行数据查询。示例代码如下: 279 280 ```c 281 OH_Predicates *likePredicates = OH_Rdb_CreatePredicates("EMPLOYEE"); 282 283 OH_VObject *likePattern = OH_Rdb_CreateValueObject(); 284 likePattern->putText(likePattern, "zh%"); 285 // 配置谓词以LIKE模式匹配 286 likePredicates->like(likePredicates, "NAME", likePattern); 287 288 char *colName[] = { "NAME", "AGE" }; 289 auto *likeQueryCursor = OH_Rdb_Query(store_, likePredicates, colName, 2); 290 likeQueryCursor->goToNextRow(likeQueryCursor); 291 size_t dataLength = 0; 292 int colIndex = -1; 293 likeQueryCursor->getColumnIndex(likeQueryCursor, "NAME", &colIndex); 294 likeQueryCursor->getSize(likeQueryCursor, colIndex, &dataLength); 295 char *name = (char*)malloc((dataLength + 1) * sizeof(char)); 296 likeQueryCursor->getText(likeQueryCursor, colIndex, name, dataLength + 1); 297 298 likeQueryCursor->destroy(likeQueryCursor); 299 likePredicates->destroy(likePredicates); 300 likePattern->destroy(likePattern); 301 free(name); 302 303 OH_Predicates *notLikePredicates = OH_Rdb_CreatePredicates("EMPLOYEE"); 304 305 // 配置谓词以NOT LIKE模式匹配 306 OH_Predicates_NotLike(notLikePredicates, "NAME", "zh%"); 307 auto *notLikeQueryCursor = OH_Rdb_Query(store_, notLikePredicates, colName, 2); 308 notLikeQueryCursor->goToNextRow(notLikeQueryCursor); 309 dataLength = 0; 310 colIndex = -1; 311 notLikeQueryCursor->getColumnIndex(notLikeQueryCursor, "NAME", &colIndex); 312 notLikeQueryCursor->getSize(notLikeQueryCursor, colIndex, &dataLength); 313 char *name2 = (char*)malloc((dataLength + 1) * sizeof(char)); 314 notLikeQueryCursor->getText(notLikeQueryCursor, colIndex, name2, dataLength + 1); 315 316 notLikeQueryCursor->destroy(notLikeQueryCursor); 317 free(name2); 318 ``` 319 配置谓词以GLOB模式或NOTGLOB模式匹配进行数据查询。示例代码如下: 320 ```c 321 OH_Predicates *globPredicates = OH_Rdb_CreatePredicates("EMPLOYEE"); 322 // 配置谓词以GLOB模式匹配 323 OH_Predicates_Glob(globPredicates, "NAME", "zh*"); 324 325 char *colName[] = { "NAME", "AGE" }; 326 auto *globQueryCursor = OH_Rdb_Query(store_, globPredicates, colName, 2); 327 globQueryCursor->goToNextRow(globQueryCursor); 328 size_t dataLength = 0; 329 int colIndex = -1; 330 globQueryCursor->getColumnIndex(globQueryCursor, "NAME", &colIndex); 331 globQueryCursor->getSize(globQueryCursor, colIndex, &dataLength); 332 char* name = (char*)malloc((dataLength + 1) * sizeof(char)); 333 globQueryCursor->getText(globQueryCursor, colIndex, name, dataLength + 1); 334 335 globQueryCursor->destroy(globQueryCursor); 336 globPredicates->destroy(globPredicates); 337 free(name); 338 339 OH_Predicates *notGlobPredicates = OH_Rdb_CreatePredicates("EMPLOYEE"); 340 // 配置谓词以NOT GLOB模式匹配 341 OH_Predicates_NotGlob(notGlobPredicates, "NAME", "zh*"); 342 auto *notGlobQueryCursor = OH_Rdb_Query(store_, notGlobPredicates, colName, 2); 343 notGlobQueryCursor->goToNextRow(notGlobQueryCursor); 344 dataLength = 0; 345 colIndex = -1; 346 notGlobQueryCursor->getColumnIndex(notGlobQueryCursor, "NAME", &colIndex); 347 notGlobQueryCursor->getSize(notGlobQueryCursor, colIndex, &dataLength); 348 char* name2 = (char*)malloc((dataLength + 1) * sizeof(char)); 349 notGlobQueryCursor->getText(notGlobQueryCursor, colIndex, name2, dataLength + 1); 350 351 notGlobQueryCursor->destroy(notGlobQueryCursor); 352 notGlobPredicates->destroy(notGlobPredicates); 353 free(name2); 354 ``` 355 如需指定排序时使用的语言规则,例如zh_CN表示中文,tr_TR表示土耳其语等。可调用OH_Rdb_SetLocale配置相应规则。 356 ```c 357 OH_Rdb_SetLocale(store_, "zh_CN"); 358 ``` 359 360 如需配置fts(Full-Text Search,即全文搜索引擎)动态库,可使用OH_Rdb_SetPlugins接口进行配置。 361 362 使用约束详见[StoreConfig](../reference/apis-arkdata/arkts-apis-data-relationalStore-i.md#storeconfig)中pluginLibs配置项。 363 364 ```c 365 const char *plugins[] = { 366 "/data/storage/el1/bundle/libs/arm64/libtokenizer.so" 367 }; 368 369 int32_t count = sizeof(plugins) / sizeof(plugins[0]); 370 auto setResult = OH_Rdb_SetPlugins(config, plugins, count); 371 ``` 3725. 使用事务对象进行插入、删除或更新数据操作。 373 374 调用OH_RdbTransOption_SetType方法,配置要创建的事务类型, 375 支持配置的事务类型有DEFERRED、IMMEDIATE和EXCLUSIVE,默认为DEFERRED。 376 377 调用OH_Rdb_CreateTransaction方法创建事务对象,使用该事务对象执行相应事务操作。 378 379 ```c 380 OH_RDB_TransOptions *options; 381 options = OH_RdbTrans_CreateOptions(); 382 // 配置事务类型 383 OH_RdbTransOption_SetType(options, RDB_TRANS_DEFERRED); 384 OH_Rdb_Transaction *trans = nullptr; 385 // 创建事务对象 386 int ret = OH_Rdb_CreateTransaction(store_, options, &trans); 387 388 OH_RdbTrans_DestroyOptions(options); 389 390 char transCreateTableSql[] = 391 "CREATE TABLE IF NOT EXISTS transaction_table (id INTEGER PRIMARY KEY AUTOINCREMENT, data1 INTEGER, " 392 "data2 INTEGER, data3 FLOAT, data4 TEXT, data5 BLOB, data6 ASSET, data7 ASSETS, data8 UNLIMITED INT, " 393 "data9 FLOATVECTOR);"; 394 395 auto *execResult = OH_Value_Create(); 396 397 // 通过事务对象执行创建数据库表SQL语句 398 ret = OH_RdbTrans_Execute(trans, transCreateTableSql, nullptr, &execResult); 399 400 // 创建OH_Data_Values实例 401 OH_Data_Values *values = OH_Values_Create(); 402 ret = OH_Values_PutInt(values, 1); 403 ret = OH_Values_PutInt(values, 2); 404 ret = OH_Values_PutReal(values, 1.1); 405 ret = OH_Values_PutText(values, "1"); 406 unsigned char val[] = {1, 2}; 407 ret = OH_Values_PutBlob(values, val, sizeof(val) / sizeof(val[0])); 408 409 Data_Asset *asset = OH_Data_Asset_CreateOne(); 410 ret = OH_Data_Asset_SetName(asset, "name"); 411 ret = OH_Values_PutAsset(values, asset); 412 OH_Data_Asset_DestroyOne(asset); 413 414 Data_Asset **assets = OH_Data_Asset_CreateMultiple(2); 415 ret = OH_Data_Asset_SetName(assets[0], "name1"); 416 ret = OH_Data_Asset_SetName(assets[1], "name2"); 417 ret = OH_Values_PutAssets(values, assets, 2); 418 ret = OH_Data_Asset_DestroyMultiple(assets, 2); 419 420 uint64_t bigInt[] = {1, 2, 3, 4, 5}; 421 ret = OH_Values_PutUnlimitedInt(values, 0, bigInt, sizeof(bigInt) / sizeof(bigInt[0])); 422 423 const char *insertSql = "INSERT INTO transaction_table " 424 "(data1, data2, data3, data4, data5, data6, data7, data8) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; 425 OH_Data_Value *outValue = nullptr; 426 427 // 通过事务对象执行数据插入SQL语句 428 ret = OH_RdbTrans_Execute(trans, insertSql, values, &outValue); 429 OH_Value_Destroy(outValue); 430 OH_Values_Destroy(values); 431 432 OH_VBucket *transValueBucket = OH_Rdb_CreateValuesBucket(); 433 transValueBucket->putInt64(transValueBucket, "data1", 1); 434 transValueBucket->putInt64(transValueBucket, "data2", 2); 435 transValueBucket->putReal(transValueBucket, "data3", 1.1); 436 transValueBucket->putText(transValueBucket, "data4", "1"); 437 transValueBucket->putBlob(transValueBucket, "data5", val, sizeof(val) / sizeof(val[0])); 438 int64_t insertRowId = -1; 439 // 通过事务对象执行OH_VBucket数据插入 440 int insertRet = OH_RdbTrans_Insert(trans, "transaction_table", transValueBucket, &insertRowId); 441 transValueBucket->destroy(transValueBucket); 442 443 OH_VBucket *transValueBucket2 = OH_Rdb_CreateValuesBucket(); 444 transValueBucket2->putInt64(transValueBucket2, "id", 1); 445 transValueBucket2->putInt64(transValueBucket2, "data2", 2); 446 transValueBucket2->putReal(transValueBucket2, "data3", 1.2); 447 448 int64_t transInsertRow = -1; 449 // 支持插入数据时配置冲突策略 450 int result = OH_RdbTrans_InsertWithConflictResolution( 451 trans, "transaction_table", transValueBucket2, Rdb_ConflictResolution::RDB_CONFLICT_REPLACE, &transInsertRow); 452 453 transValueBucket2->destroy(transValueBucket2); 454 455 OH_VBucket *transValueBucket3 = OH_Rdb_CreateValuesBucket(); 456 transValueBucket3->putInt64(transValueBucket3, "id", 1); 457 transValueBucket3->putInt64(transValueBucket3, "data2", 3); 458 transValueBucket3->putReal(transValueBucket3, "data3", 1.2); 459 460 OH_Predicates *transUpdatePredicates = OH_Rdb_CreatePredicates("transaction_table"); 461 auto targetValue = OH_Rdb_CreateValueObject(); 462 int64_t two = 2; 463 targetValue->putInt64(targetValue, &two, 1); 464 transUpdatePredicates->equalTo(transUpdatePredicates, "data2", targetValue); 465 466 int64_t updateRows = -1; 467 // 支持更新数据时配置冲突策略 468 OH_RdbTrans_UpdateWithConflictResolution(trans, transValueBucket3, transUpdatePredicates, 469 Rdb_ConflictResolution::RDB_CONFLICT_REPLACE, &updateRows); 470 targetValue->destroy(targetValue); 471 transValueBucket3->destroy(transValueBucket3); 472 transUpdatePredicates->destroy(transUpdatePredicates); 473 474 OH_Predicates *predicates = OH_Rdb_CreatePredicates("transaction_table"); 475 const char *columns[] = {"data1", "data2", "data3"}; 476 // 通过事务对象执行数据查询 477 OH_Cursor *cursor = OH_RdbTrans_Query(trans, predicates, columns, sizeof(columns) / sizeof(columns[0])); 478 int columnCount = 0; 479 cursor->getColumnCount(cursor, &columnCount); 480 481 predicates->destroy(predicates); 482 cursor->destroy(cursor); 483 484 OH_Predicates *predicates2 = OH_Rdb_CreatePredicates("transaction_table"); 485 OH_VObject *valueObject = OH_Rdb_CreateValueObject(); 486 valueObject->putText(valueObject, "1"); 487 predicates2->equalTo(predicates2, "data4", valueObject); 488 int64_t changes = -1; 489 // 通过事务对象执行数据删除 490 int deleteRet = OH_RdbTrans_Delete(trans, predicates2, &changes); 491 predicates2->destroy(predicates2); 492 valueObject->destroy(valueObject); 493 494 // 提交事务 495 OH_RdbTrans_Commit(trans); 496 // 销毁事务 497 OH_RdbTrans_Destroy(trans); 498 ``` 499 500 ```c 501 OH_RDB_TransOptions *options2; 502 options2 = OH_RdbTrans_CreateOptions(); 503 OH_RdbTransOption_SetType(options2, RDB_TRANS_DEFERRED); 504 OH_Rdb_Transaction *trans2 = nullptr; 505 int transCreateRet = OH_Rdb_CreateTransaction(store_, options2, &trans2); 506 OH_RdbTrans_DestroyOptions(options2); 507 508 // 回滚事务 509 OH_RdbTrans_Rollback(trans2); 510 OH_RdbTrans_Destroy(trans2); 511 512 ``` 513 5146. 附加数据库。 515 516 调用OH_Rdb_Attach将一个数据库文件附加到当前数据库中,以便在SQL语句中可以直接访问附加数据库中的数据。 517 此API不支持附加加密数据库。 518 519 调用attach接口后,数据库切换为非WAL模式,性能会存在一定的劣化。切换模式需要确保所有的OH_Cursor都已经销毁,所有的写操作已经结束,否则会报错14800015。 520 521 attach不能并发调用,可能出现未响应情况,报错14800015,需要重试。 522 523 当不再使用附加数据时,可调用OH_Rdb_Detach分离附加数据库。 524 525 ```c 526 char attachStoreTableCreateSql[] = "CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, " 527 "AGE INTEGER, SALARY REAL, CODES BLOB)"; 528 OH_Rdb_ConfigV2* configAttach = OH_Rdb_CreateConfig(); 529 OH_Rdb_SetModuleName(configAttach, "entry"); 530 OH_Rdb_SetDatabaseDir(configAttach, "/data/storage/el2/database"); 531 OH_Rdb_SetArea(configAttach, RDB_SECURITY_AREA_EL2); 532 OH_Rdb_SetStoreName(configAttach, "RdbAttach.db"); 533 OH_Rdb_SetSecurityLevel(configAttach, OH_Rdb_SecurityLevel::S3); 534 OH_Rdb_SetBundleName(configAttach, "com.example.nativedemo"); 535 536 // 创建示例 RdbAttach.db 537 int attachStoreCreateErrCode = 0; 538 OH_Rdb_Store *attachStore = OH_Rdb_CreateOrOpen(configAttach, &attachStoreCreateErrCode); 539 OH_Rdb_Execute(attachStore, attachStoreTableCreateSql); 540 OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket(); 541 valueBucket->putText(valueBucket, "NAME", "Lisa"); 542 valueBucket->putInt64(valueBucket, "AGE", 18); 543 valueBucket->putReal(valueBucket, "SALARY", 100.5); 544 uint8_t arr[] = {1, 2, 3, 4, 5}; 545 int len = sizeof(arr) / sizeof(arr[0]); 546 valueBucket->putBlob(valueBucket, "CODES", arr, len); 547 int rowId = OH_Rdb_Insert(attachStore, "EMPLOYEE", valueBucket); 548 valueBucket->destroy(valueBucket); 549 OH_Rdb_CloseStore(attachStore); 550 551 // 附加数据库 552 size_t attachedCount = 0; 553 int result = OH_Rdb_Attach(store_, configAttach, "attach", 10, &attachedCount); 554 auto predicates = OH_Rdb_CreatePredicates("attach.EMPLOYEE"); 555 char *colName[] = {}; 556 auto cursor = OH_Rdb_Query(store_, predicates, colName, 0); 557 int rowCount = -1; 558 result = cursor->getRowCount(cursor, &rowCount); 559 cursor->destroy(cursor); 560 561 // 分离数据库 562 result = OH_Rdb_Detach(store_, "attach", 10, &attachedCount); 563 ``` 564 5657. 向数据库表中插入资产类型数据。 566 567 ```c 568 // 列的属性为单个资产类型时,sql语句中应指定为asset,多个资产类型应指定为assets。 569 char createAssetTableSql[] = "CREATE TABLE IF NOT EXISTS asset_table (id INTEGER PRIMARY KEY AUTOINCREMENT, data1 asset, data2 assets );"; 570 const char *table = "asset_table"; 571 int errCode = OH_Rdb_Execute(store_, createAssetTableSql); 572 OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket(); 573 Data_Asset *asset = OH_Data_Asset_CreateOne(); 574 OH_Data_Asset_SetName(asset, "name0"); 575 OH_Data_Asset_SetUri(asset, "uri0"); 576 OH_Data_Asset_SetPath(asset, "path0"); 577 OH_Data_Asset_SetCreateTime(asset, 1); 578 OH_Data_Asset_SetModifyTime(asset, 1); 579 OH_Data_Asset_SetSize(asset, 1); 580 OH_Data_Asset_SetStatus(asset, Data_AssetStatus::ASSET_NORMAL); 581 errCode = OH_VBucket_PutAsset(valueBucket, "data1", asset); 582 583 Data_Asset **assets = OH_Data_Asset_CreateMultiple(2); 584 585 OH_Data_Asset_SetName(assets[0], "name0"); 586 OH_Data_Asset_SetUri(assets[0], "uri0"); 587 OH_Data_Asset_SetPath(assets[0], "path0"); 588 OH_Data_Asset_SetCreateTime(assets[0], 1); 589 OH_Data_Asset_SetModifyTime(assets[0], 1); 590 OH_Data_Asset_SetSize(assets[0], 1); 591 OH_Data_Asset_SetStatus(assets[0], Data_AssetStatus::ASSET_NORMAL); 592 593 OH_Data_Asset_SetName(assets[1], "name1"); 594 OH_Data_Asset_SetUri(assets[1], "uri1"); 595 OH_Data_Asset_SetPath(assets[1], "path1"); 596 OH_Data_Asset_SetCreateTime(assets[1], 1); 597 OH_Data_Asset_SetModifyTime(assets[1], 1); 598 OH_Data_Asset_SetSize(assets[1], 1); 599 OH_Data_Asset_SetStatus(assets[1], Data_AssetStatus::ASSET_NORMAL); 600 601 uint32_t assetsCount = 1; 602 errCode = OH_VBucket_PutAssets(valueBucket, "data2", assets, assetsCount); 603 int rowID = OH_Rdb_Insert(store_, table, valueBucket); 604 // 释放Data_Asset*和Data_Asset** 605 OH_Data_Asset_DestroyMultiple(assets, 2); 606 OH_Data_Asset_DestroyOne(asset); 607 valueBucket->destroy(valueBucket); 608 ``` 609 6108. 从结果集中读取资产类型数据。 611 612 ```c 613 OH_Predicates *predicates = OH_Rdb_CreatePredicates("asset_table"); 614 615 OH_Cursor *cursor = OH_Rdb_Query(store_, predicates, NULL, 0); 616 cursor->goToNextRow(cursor); 617 618 uint32_t assetCount = 0; 619 // assetCount作为出参获取该列资产类型数据的数量 620 int errCode = cursor->getAssets(cursor, 2, nullptr, &assetCount); 621 Data_Asset **assets = OH_Data_Asset_CreateMultiple(assetCount); 622 errCode = cursor->getAssets(cursor, 2, assets, &assetCount); 623 if (assetCount < 2) { 624 predicates->destroy(predicates); 625 cursor->destroy(cursor); 626 return; 627 } 628 Data_Asset *asset = assets[1]; 629 char name[10] = ""; 630 size_t nameLength = 10; 631 errCode = OH_Data_Asset_GetName(asset, name, &nameLength); 632 633 char uri[10] = ""; 634 size_t uriLength = 10; 635 errCode = OH_Data_Asset_GetUri(asset, uri, &uriLength); 636 637 char path[10] = ""; 638 size_t pathLength = 10; 639 errCode = OH_Data_Asset_GetPath(asset, path, &pathLength); 640 641 int64_t createTime = 0; 642 errCode = OH_Data_Asset_GetCreateTime(asset, &createTime); 643 644 int64_t modifyTime = 0; 645 errCode = OH_Data_Asset_GetModifyTime(asset, &modifyTime); 646 647 size_t size = 0; 648 errCode = OH_Data_Asset_GetSize(asset, &size); 649 650 Data_AssetStatus status = Data_AssetStatus::ASSET_NULL; 651 errCode = OH_Data_Asset_GetStatus(asset, &status); 652 653 predicates->destroy(predicates); 654 OH_Data_Asset_DestroyMultiple(assets, assetCount); 655 cursor->destroy(cursor); 656 ``` 657 6589. 查询数据的最后修改时间。调用OH_Rdb_FindModifyTime查询指定表中指定列的数据的最后修改时间,该接口返回一个有两列数据的OH_Cursor对象,第一列为传入的主键/RowId,第二列为最后修改时间。示例代码如下所示: 659 660 ```c 661 OH_VObject *values = OH_Rdb_CreateValueObject(); 662 int64_t keys[] = { 1 }; 663 values->putInt64(values, keys, 1); 664 OH_Cursor *cursor; 665 cursor = OH_Rdb_FindModifyTime(store_, "EMPLOYEE", "ROWID", values); 666 ``` 667 66810. 删除数据库。调用OH_Rdb_DeleteStore方法,删除数据库及数据库相关文件。示例代码如下: 669 670 ```c 671 // 释放数据库实例 672 OH_Rdb_CloseStore(store_); 673 // 删除数据库文件 674 OH_Rdb_DeleteStoreV2(config); 675 ``` 676