• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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