提交 d741b8fe 编写于 作者: A Annie_wang

update docs

Signed-off-by: NAnnie_wang <annie.wangli@huawei.com>
上级 777a0177
......@@ -38,7 +38,6 @@
- [Multimedia](subsystems/subsys-multimedia-camera-overview.md)
- [Utils](subsystems/subsys-utils-overview.md)
- [AI Framework](subsystems/subsys-ai-aiframework-devguide.md)
- [Data Management](subsystems/subsys-data-relational-database-overview.md)
- [Sensor](subsystems/subsys-sensor-overview.md)
- [Application Framework](subsystems/subsys-application-framework-overview.md)
- [OTA Update](subsystems/subsys-ota-guide.md)
......
......@@ -44,13 +44,6 @@
- AI
- [AI Framework Development](subsys-ai-aiframework-devguide.md)
- [NNRt Development](subsys-ai-nnrt-guide.md)
- Data Management
- RDB
- [RDB Overview](subsys-data-relational-database-overview.md)
- [RDB Development](subsys-data-relational-database-guide.md)
- Lightweight Data Store
- [Lightweight Data Store Overview](subsys-data-storage-overview.md)
- [Lightweight Data Store Development](subsys-data-storage-guide.md)
- Sensor
- [Sensor Overview](subsys-sensor-overview.md)
- [Sensor Usage Guidelines](subsys-sensor-guide.md)
......
# RDB Development
## When to Use
A relational database (RDB) store allows you to operate local data with or without native SQL statements based on SQLite.
## Available APIs
### Creating and Deleting an RDB Store
The table below describes the APIs for creating and deleting an RDB store.
**Table 1** APIs for creating and deleting an RDB store
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStoreConfig | RdbStoreConfig(const std::string &path, <br> StorageMode storageMode = StorageMode::MODE_DISK, <br> bool readOnly = false, <br> const std::vector<uint8_t> &encryptKey = std::vector<uint8_t>(), <br> const std::string &journalMode = "", <br> const std::string &syncMode = "", <br> const std::string &databaseFileType = "", <br> const std::string &databaseFileSecurityLevel = "") | Configures an RDB store, including setting the RDB store name, storage mode, log mode, synchronization mode, and read-only mode, and whether to encrypt the RDB store.<br/> - **path**: path of the RDB store. <br>- **readOnly**: whether the RDB store is read-only. <br>- **storageMode**: storage mode. <br>- **encryptKey**: key used to encrypt the RDB store. <br>- **journalMode**: logging mode. <br>- **syncMode**: data synchronization mode. <br>- **databaseFileType**: RDB store type. <br>- **databaseFileSecurityLevel**: security level of the RDB store.|
| RdbOpenCallback | int OnCreate(RdbStore &rdbStore) | Called when an RDB store is created. You can add the method for initializing the table structure and initialization data used by your application in this callback.|
| RdbOpenCallback | int OnUpgrade(RdbStore &rdbStore, int currentVersion, int targetVersion) | Called when the RDB store is upgraded.|
| RdbOpenCallback | int OnDowngrade(RdbStore &rdbStore, int currentVersion, int targetVersion) | Called when the RDB store is downgraded.|
| RdbHelper | std::shared_ptr\<RdbStore\> GetRdbStore(const RdbStoreConfig &config, int version, RdbOpenCallback &openCallback, int &errCode) | Creates or obtains an RDB store.|
| RdbHelper | int DeleteRdbStore(const std::string &path) | Deletes an RDB store.|
### Encrypting an RDB Store
When creating an RDB store, you can add a key for security purposes. After that, the RDB store can be accessed only with the correct key.
**Table 2** API for changing the key
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | int ChangeEncryptKey(const std::vector<uint8_t> &newKey) | Changes the encryption key for an RDB store. <br>Note that the encryption key can be changed only for an encrypted RDB store.|
### Using Predicates
The RDB store provides **AbsRdbPredicates** for you to set database operation conditions. The **AbsRdbPredicates** class has the following child classes:
- **RdbPredicates**: allows you to combine SQL statements by simply calling methods in this class, such as **equalTo**, **notEqualTo**, **groupBy**, **orderByAsc**, and **beginsWith**. With this class, you do not need to write complex SQL statements.
- **RawRdbPredicates**: allows you to write complex SQL statements, such as setting **whereClause** and **whereArgs**. However, this class does not support APIs such as **equalTo**.
**Table 3** APIs for setting RDB predicates
| Class| API| Description|
| ---- | ---- | ---- |
| RdbPredicates | AbsPredicates *EqualTo(std::string field, std::string value) | Sets an **AbsPredicates** to match the field that is equal to the specified value.|
| RdbPredicates | AbsPredicates *NotEqualTo(std::string field, std::string value) | Sets an **AbsPredicates** to match the field that is not equal to the specified value.|
| RdbPredicates | AbsPredicates *BeginsWith(std::string field, std::string value) | Sets an **AbsPredicates** to match the field that starts with the specified value.|
| RdbPredicates | AbsPredicates *Between(std::string field, std::string low, std::string high) | Sets an **AbsPredicates** to match the field that is within the range specified by **low** and **high**.|
| RdbPredicates | AbsPredicates *OrderByAsc(std::string field) | Sets an **AbsPredicates** that sorts values in ascending order.|
| RdbPredicates | void SetWhereClause(std::string whereClause) | Sets **whereClause**.|
| RdbPredicates | void SetWhereArgs(std::vector\<std::string\> whereArgs) | Sets **whereArgs**, which indicates the value of the placeholder in **whereClause**.|
| RdbPredicates | AbsRdbPredicates *InDevices(std::vector<std::string>& devices) | Sets an **AbsPredicates** to specify the remote devices on the network with databases to be synchronized.|
| RdbPredicates | AbsRdbPredicates *InAllDevices() | Sets an **AbsPredicates** to connect to all remote devices on the network when synchronizing distributed databases.|
### Managing Data in an RDB Store
You can use the APIs provided by the RDB to insert, delete, update, and query local data.
- Inserting data
Call **int Insert()** to insert data through **ValuesBucket**. If data is inserted, the row number of the data inserted is returned; otherwise, **-1** is returned.
**Table 4** API for inserting data
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | int Insert(int64_t &outRowId, const std::string &table, const ValuesBucket &initialValues) | Inserts data based on the passed table name and data in **ValuesBucket**. <br/>- **table**: name of the target table. <br/>- **initialValues**: data to insert. The data is stored in **ValuesBucket**. A series of **put()** methods, such as **PutString(const std::string &columnName, const std::string &value)** and **PutDouble(const std::string &columnName, double value)**, are provided to add data to **ValuesBucket**. |
- Deleting data
Call **delete()** to delete the data that meets the conditions specified by **AbsRdbPredicates**. If data is deleted, the row number of the deleted data is returned; otherwise, **0** is returned.
**Table 5** API for deleting data
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | int Delete(int &deletedRows, const AbsRdbPredicates &predicates) | Deletes data.<br> - **deletedRows**: number of rows to delete.<br> - **predicates**: table name and conditions for deleting the data. **AbsRdbPredicates** has the following classes:<br> - **RdbPredicates**: specifies query conditions by calling its methods, such as **equalTo**.<br> - **RawRdbPredicates**: specifies the table name, **whereClause**, and **whereArgs** only. |
- Updating data
Call **update()** to update data based on the passed data and the conditions specified by **AbsRdbPredicates**. If data is updated, the row number of the updated data is returned; otherwise, **0** is returned.
**Table 6** API for updating data
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | int Update(int &changedRows, const ValuesBucket &values, const AbsRdbPredicates &predicates) | Updates the data that meets the conditions specified by predicates.<br> - **changedRows**: number of rows to update.<br> - **values**: new data stored in **ValuesBucket**.<br> - **predicates**: table name and conditions for the update operation. **AbsRdbPredicates** has the following classes:<br> - **RdbPredicates**: specifies update conditions by calling its methods, such as **equalTo**.<br> - **RawRdbPredicates**: specifies the table name, **whereClause**, and **whereArgs** only. |
- Querying data
You can query data in an RDB store in either of the following ways:
- Call the **query()** method to query data based on the predicates, without passing any SQL statement.
- Run the native SQL statement.
**Table 7** APIs for querying data
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | std::unique_ptr<AbsSharedResultSet> Query(const AbsRdbPredicates &predicates, const std::vector\<std::string\> columns) | Queries data.<br> - **predicates**: query conditions. **AbsRdbPredicates** has the following classes:<br> - **RdbPredicates**: specifies query conditions by calling its methods, such as **equalTo**.<br> - **RawRdbPredicates**: specifies the table name, **whereClause**, and **whereArgs** only.<br> - **columns**: number of columns returned. |
| RdbStore | std::unique_ptr<AbsSharedResultSet> QuerySql(const std::string &sql, const std::vector\<std::string\> &selectionArgs = std::vector\<std::string\>()) | Executes the native SQL statements to query data.<br> - **sql**: native SQL statement.<br> - **selectionArgs**: parameter values corresponding to the placeholders in the SQL statements. Set it to **null** if the **select** statement has no placeholder. |
### Obtaining the Query Result
You can use the APIs provided by **ResultSet** to traverse and access the data you have queried. A result set can be regarded as a row of data in the queried result. The table below describes the APIs of **ResultSet**.
**Table 8** APIs of **ResultSet**
| Class| API| Description|
| ---- | ---- | ---- |
| ResultSet | int GoTo(int offset) | Moves forwards or backwards by the specified offset relative to its current position.|
| ResultSet | int GoToRow(int position) | Moves to the specified row.|
| ResultSet | int GoToNextRow() | Moves to the next row.|
| ResultSet | int GoToPreviousRow() | Moves to the previous row.|
| ResultSet | int IsStarted(bool &result) | Checks whether the result set has been moved.|
| ResultSet | int IsEnded(bool &result) | Checks whether the result set is moved after the last line.|
| ResultSet | int IsAtFirstRow(bool &result) | Checks whether the result set is located in the first row.|
| ResultSet | int IsAtLastRow(bool &result) | Checks whether the result set is located in the last row.|
| ResultSet | int GetRowCount(int &count) | Obtains the number of rows of this result set.|
| ResultSet | int GetColumnCount(int &count) | Obtains the number of columns of this result set.|
| ResultSet | int GetString(int columnIndex, std::string &value) | Obtains the value in the specified column of the current row, in strings.|
| ResultSet | int GetBlob(int columnIndex, std::vector\<uint8_t\> &blob) | Obtains the value in the specified column of the current row, in a byte array.|
| ResultSet | int GetDouble(int columnIndex, double &value) | Obtains the value in the specified column of the current row, in double.|
### Setting Distributed Tables
Call **bool SetDistributedTables()** to set distributed tables for data operations across devices.
**Table 9** API for setting distributed tables
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | bool SetDistributedTables(const std::vector<std::string>& tables) | Sets distributed tables.<br> **tables**: names of the distributed tables to set. |
### Obtaining the Distributed Table Name for a Remote Device
You can obtain the distributed table name for a remote device based on the local table name. The distributed table name can be used to query the RDB store of the remote device.<br>
**Table 10** API for obtaining the distributed table name of a remote device
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | std::string ObtainDistributedTableName(const std::string& device, const std::string& table) | Obtains the distributed table name of a remote device based on the local table name. The distributed table name can be used to query the RDB store of the remote device.<br> - **device**: ID of the remote device. <br>- **table**: name of the local table.|
### Synchronizing Data Between Devices
**Table 11** API for synchronizing data between devices
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | bool Sync(const SyncOption& option, const AbsRdbPredicates& predicate, const SyncCallback& callback) | Synchronizes data between devices. <br/>- **option**: synchronization options, which include **mode** and **isBlock**. **mode** specifies how data is synchronized. The value **push** means to push data from the local device to the remote device; the value **pull** means to pull data from the remote device to the local device. **isBlock** specifies whether the invocation of this function is blocked. <br>- **callback**: callback used to return the result. |
### Registering an RDB Store Observer
**Table 12** API for registering an observer
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | bool Subscribe(const SubscribeOption& option, RdbStoreObserver *observer) | Registers an observer for this RDB store to listen for distributed data changes. When data in the RDB store changes, a callback will be invoked to return the data changes. <br/>- **option**: subscription type.<br>- **observer**: observer that listens for data changes in the RDB store. |
### Unregistering an RDB Store Observer
**Table 13** API for unregistering an observer
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | bool UnSubscribe(const SubscribeOption& option, RdbStoreObserver *observer) | Unregisters the observer of the specified type. <br/>- **option**: subscription type to unregister.<br>- **observer**: observer to unregister. |
### Backing Up and Restoring an RDB Store
You can use the APIs provided by **rdbStore** to back up and restore local database files.
- Backing up an RDB store
Call **int Backup()** to back up the current database file. **databasePath** specifies the name or path of the backup file to be generated. If the backup is successful, **0** is returned; otherwise, an error code is returned.
Table 14 API for backing up an RDB store
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | int Backup(const std::string databasePath, const std::vector&lt;uint8_t&gt; destEncryptKey) | Backs up the current database file.<br>- **databasePath**: name or path of the backup file to generate.<br>- **destEncryptKey**: key used to encrypt the RDB store. Currently, only non-encrypted RDB stores can be backed up. |
- Restoring an RDB store
Call **int Restore()** to restore an RDB from the backup file. **backupPath** specifies the name or path of the backup file. If the restore is successful, **0** is returned; otherwise, an error code is returned.
Table 15 API for restoring an RDB store
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | int Restore(const std::string backupPath, const std::vector&lt;uint8_t&gt; &newKey) | Restore an RDB store.<br> - **backupPath**: name or path of the backup file.<br> - **newKey**: key used to encrypt the RDB store. Currently, only non-encrypted RDB stores can be restored. |
### Transaction
A transaction is a unit of work performed in a database. If a transaction is successful, **0** is returned. Otherwise, an error code is returned.
Table 16 Transaction APIs
| Class| API| Description|
| ---- | ---- | ---- |
| RdbStore | int BeginTransaction() | Starts a transaction.|
| RdbStore | int Commit() | Commits the changes.|
| RdbStore | int RollBack() | Rolls back the changes.|
## Constraints
None.
## How to Develop
1. Create an RDB store.
a. Configure the RDB store attributes, including the RDB store name, storage mode, and read-only mode.
b. Initialize the table structure and related data in the RDB store.
c. Create an RDB store.
The sample code is as follows:
```c++
const std::string DATABASE_NAME = RDB_TEST_PATH + "RdbStoreTest.db";
const std::string CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, salary REAL, blobType BLOB)";
class OpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
};
int OpenCallback::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CREATE_TABLE_TEST);
}
RdbStoreConfig config(DATABASE_NAME);
OpenCallback callback;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, callback, 0);
```
2. Insert data.
a. Create a **ValuesBucket** to store the data you need to insert.
b. Call the **insert()** method to insert data into the RDB store.
c. Create an RDB store.
The sample code is as follows:
```c++
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("Tom"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
store->Insert(id, "test", values);
```
3. Query data.
a. Create a predicate that specifies query conditions.
b. Specify the data columns to return in the result set.
c. Call the **query()** method to query data.
d. Call the **ResultSet** APIs to traverse data in the result set.
The sample code is as follows:
```c++
std::vector<std::string> columns = {"id", "name", "age", "salary"};
RdbPredicates predicates("test");
predicates.EqualTo("age", "25")->OrderByAsc("salary");
std::unique_ptr<ResultSet> resultSet = store->Query(predicates, columns)
resultSet.goToNextRow();
```
4. Set the distributed tables to be synchronized.
Call the **SetDistributedTables()** method to set the distributed tables to be synchronized.
The sample code is as follows:
```c++
store->SetDistributedTables("test");
```
5. Synchronize data.
a. Set the data synchronization mode and block status.
b. Constructs an **AbsPredicates** object to specify remote devices within the network to be synchronized.
c. Call the **Sync()** method to synchronize data.
The sample code is as follows:
```c++
SyncOption option;
option.mode = PUSH;
option.isBlock = true;
AbsRdbPredicates predicate("test");
predicate.InAllDevices();
store->Sync(option, predicate, [] (const SyncResult& result) {
for (const auto& [device, status] : result) {
LogI("device=%s status=%d", device.c_str(), status);
}
});
```
6. Subscribe to distributed data.
a. Override the **OnChange()** function.
b. Define the distributed data subscription type.
c. Call APIs to subscribe to or unsubscribe from distributed data.
The sample code is as follows:
```c++
class MyObserver : public RdbStoreObserver {
public:
void OnChange(const std::vector<std::string>& devices) override {
for (const auto& device : devices) {
LOGI("device=%s data change", device.c_str());
}
}
};
SubscribeOption option;
option.mode = SubscribeMode::REMOTE;
MyObserver observer;
store->Subscribe(option, &observer); // Subscribe to distributed data.
store->UnSubscribe(option, &observer); // Unsubscribe from distributed data.
```
7. Query data across devices.
a. Obtain the distributed table name for a remote device based on the local table name.
b. Run SQL statements to query data in the RDB store of the remote device.
The sample code is as follows:
```c++
std::string tableName = store->ObtainDistributedTableName("123456789abcd", "test");
auto resultSet = store->QuerySql("SELECT * from ?;", tableName);
```
8. Back up and restore an RDB store.
a. Back up the current RDB store.
b. Restore the RDB store from the specified backup file.
The sample code is as follows:
```c++
std::string backupName = "backup.db"; // Name of the database backup file to generate.
std::vector<uint8_t> key; // Key used to encrypt the RDB store.
int errno = store->Backup(backupName, key);
errno = store->Restore(backupName, key);
```
# RDB Overview
The relational database (RDB) manages data based on relational models. With the underlying SQLite database, the OpenHarmony RDB provides a complete mechanism for managing local databases. To satisfy different needs in complicated scenarios, the RDB offers a series of methods for performing operations such as adding, deleting, modifying, and querying data, and supports direct execution of SQL statements.
## Basic Concepts
- RDB
A type of database created on the basis of relational models. The RDB stores data in rows and columns.
- Predicate
A representation of the property or feature of a data entity, or the relationship between data entities. It is mainly used to define operation conditions.
- Result set
A set of query results used to access data. You can access the required data in a result set in flexible modes.
- SQLite database
A lightweight open-source relational database management system that complies with Atomicity, Consistency, Isolation, and Durability (ACID).
## Working Principles
The OpenHarmony RDB provides a common operation interface (**RdbStore**) for external systems. It uses the third-party open-source SQLite as the underlying persistent storage engine, which supports all SQLite database features.
**Figure 1** How RDB works
![](figures/en-us_image_0000001115980740.png)
## Default Settings
- The default database logging mode is write-ahead logging (WAL).
- The default database flush mode is Full mode.
- The default shared memory is 8 MB for the OpenHarmony database and 2 MB for a single query.
## Constraints
- A maximum of four connection pools can be connected to an RDB to manage read and write operations.
- To ensure data accuracy, the RDB supports only one write operation at a time.
# Lightweight Data Store Development
## When to Use
The lightweight data store is ideal for storing lightweight and frequently used data, but not for storing a large amount of data or data with frequent changes. The application data is persistently stored on a device in the form of files. Note that the instance accessed by an application contains all data of the file. The data is always loaded to the memory of the device until the application removes it from the memory. The application can perform data operations using the Preferences APIs.
## Available APIs
The lightweight data store provides applications with data processing capability and allows applications to perform lightweight data storage and query. Data is stored in key-value pairs. Keys are of the string type, and values can be of the string, Boolean, integer, long integer, float, double, or string array type.
**Creating a Preferences Instance**
Create a **Preferences** instance for data operations. A **Preferences** instance is created after data is read from a specified file and loaded to the instance.
**Table 1** API for creating a Preferences instance
| Class| Method| Description|
| --- | ----- | ----|
| PreferencesHelper | static std::shared_ptr<Preferences> GetPreferences(const std::string &path, int &errCode); | Creates a **Preferences** instance. <br>**path**: storage path of the application data.<br>**errCode**: error code.<br>Return value: **Preferences** instance created.|
**Writing Data**
Call the **put()** method to add or modify data in a **Preferences** instance.
**Table 2** APIs for writing data
| Class| Method| Description|
| --- | ----- | ----|
| Preferences | int PutInt(const std::string &key, int value); | **key**: key of the data to write. It cannot be empty.<br>**value**: value of the data to write.<br>Return value: Returns **0** if the operation is successful; returns the error code otherwise.|
| Preferences | int PutString(const std::string &key, const std::string &value); | **key**: key of the data to write. It cannot be empty.<br>**value**: value of the data to write.<br>Return value: Returns **0** if the operation is successful; returns the error code otherwise.|
| Preferences | int PutBool(const std::string &key, bool value); | **key**: key of the data to write. It cannot be empty.<br>**value**: value of the data to write.<br>Return value: Returns **0** if the operation is successful; returns the error code otherwise.|
| Preferences | int PutLong(const std::string &key, int64_t value); | **key**: key of the data to write. It cannot be empty.<br>**value**: value of the data to write.<br>Return value: Returns **0** if the operation is successful; returns the error code otherwise.|
| Preferences | int PutFloat(const std::string &key, float value); | **key**: key of the data to write. It cannot be empty.<br>**value**: value of the data to write.<br>Return value: Returns **0** if the operation is successful; returns the error code otherwise.|
| Preferences | int PutDouble(const std::string &key, double value); | **key**: key of the data to write. It cannot be empty.<br>**value**: value of the data to write.<br>Return value: Returns **0** if the operation is successful; returns the error code otherwise.|
| Preferences | int PutStringSet(const std::string &key, const std::set\<std::string\> &value); | **key**: key of the data to write. It cannot be empty.<br>**value**: value of the data to write.<br>Return value: Returns **0** if the operation is successful; returns the error code otherwise.|
**Reading Data**
Call the **get()** method to read data from a **Preferences** instance.
**Table 3** APIs for reading data
| Class| Method| Description|
| --- | ----- | ----|
| Preferences | int GetInt(const std::string &key, const int defValue = 0); | **key**: key of the data to read. It cannot be empty.<br>**defValue**: default value to return if the operation fails or the value does not exist.<br>Return value: value obtained.|
| Preferences | std::string GetString(const std::string &key, const std::string &defValue = {}); | **key**: key of the data to read. It cannot be empty.<br>**defValue**: default value to return if the operation fails or the value does not exist.<br>Return value: value obtained.|
| Preferences | bool GetBool(const std::string &key, const bool defValue = false); | **key**: key of the data to read. It cannot be empty.<br>**defValue**: default value to return if the operation fails or the value does not exist.<br>Return value: value obtained.|
| Preferences | float GetFloat(const std::string &key, const float defValue = 0); | **key**: key of the data to read. It cannot be empty.<br>**defValue**: default value to return if the operation fails or the value does not exist.<br>Return value: value obtained.|
| Preferences | double GetDouble(const std::string &key, const double defValue = 0); | **key**: key of the data to read. It cannot be empty.<br>**defValue**: default value to return if the operation fails or the value does not exist.<br>Return value: value obtained.|
| Preferences | int64_t GetLong(const std::string &key, const int64_t defValue = 0); | **key**: key of the data to read. It cannot be empty.<br>**defValue**: default value to return if the operation fails or the value does not exist.<br>Return value: value obtained.|
| Preferences | std::set\<std::string\> GetStringSet(const std::string &key, const std::set\<std::string\> &defValue = {}); | **key**: key of the data to read. It cannot be empty.<br>**defValue**: default value to return if the operation fails or the value does not exist.<br>Return value: value obtained.|
**Storing Data Persistently**
Call the **Flush()** or **FlushSync()** method to write the cached data back to its text file for persistent storage.
**Table 4** APIs for data persistence
| Class| Method| Description|
| --- | ----- | ----|
| Preferences | void Flush(); | Writes data in the **Preferences** instance back to its file through an asynchronous thread.|
| Preferences | int FlushSync(); | Writes data in the **Preferences** instance back to its file through a synchronous thread.|
**Observing Data Changes**
Specify **PreferencesObserver** as the callback to subscribe to data changes. When the value of the subscribed key is changed and the **flush()** method is executed, **PreferencesObserver** will be invoked.
**Table 5** APIs for observing data changes
| Class| Method| Description|
| --- | ----- | ----|
| Preferences | void RegisterObserver(std::shared_ptr<PreferencesObserver> preferencesObserver); | Subscribes to data changes. <br>**preferencesObserver**: callback invoked to return the data changes.|
| Preferences | void UnRegisterObserver(std::shared_ptr<PreferencesObserver> preferencesObserver); | Unsubscribes from data changes. <br>**preferencesObserver**: callback used to report data changes.|
**Deleting Data**
Use the following APIs to delete a **Preferences** instance or data file.
**Table 6** APIs for deleting data
| Class| Method| Description|
| --- | ----- | ----|
| PreferencesHelper | int DeletePreferences(const std::string &path); | Deletes a **Preferences** instance from the memory and deletes its file from the device. <br>**path**: storage path of the application data.<br>Return value: Returns **0** if the operation is successful; returns the error code otherwise.|
| PreferencesHelper | int RemovePreferencesFromCache(const std::string &path); | Deletes a **Preferences** instance from the memory. <br>**path**: storage path of the application data.<br>Return value: Returns **0** if the operation is successful; returns the error code otherwise.|
## How to Develop
1. Import the Preferences module and related header files to the development environment.
``` C++
Header file path: //distributeddatamgr_appdatamgr/interfaces/innerkits/native_preferences/include
```
2. Create a **Preferences** instance.
Read the specified file and load its data to the **Preferences** instance for data operations.
``` C++
int errCode = E_OK;
Preferences pref = PreferencesHelper::GetPreferences(PREF_TEST_PATH + "test.xml", errCode); // PREF_TEST_PATH must be the application sandbox path.
EXPECT_EQ(errCode, E_OK);
```
3. Write data.
Use the **put()** method of the **Preferences** class to write data to the cached **Preferences** instance.
```C++
pref->PutString("test", "remove");
```
4. Read data.
Use the **get()** method of the **Preferences** class to read data.
``` C++
std::string ret = pref->GetString("test", "defaultValue");
EXPECT_EQ(ret, "remove");
```
5. Store data persistently.
Use the **Flush()** or **FlushSync()** method to flush data in the **Preferences** instance to its file.
```C++
int err = pref->FlushSync();
EXPECT_EQ(ret, E_OK);
```
6. Subscribe to data changes.
Specify **PreferencesObserver** as the callback to subscribe to data changes for an application. When the value of the subscribed key is changed and the **flush()** or **flushSync()** method is executed, **PreferencesObserver** will be invoked. Unregister the **PreferencesObserver** when it is no longer required.
Customize a class to implement the **PreferencesObserver**:
``` C++
class PreferencesObserverCounter : public PreferencesObserver {
public:
virtual ~PreferencesObserverCounter();
void OnChange(Preferences &preferences, const std::string &key) override;
std::atomic_int notifyTimes;
static const std::vector<std::string> NOTIFY_KEYS_VECTOR;
};
PreferencesObserverCounter::~PreferencesObserverCounter() {}
void PreferencesObserverCounter::OnChange(Preferences &preferences, const std::string &key)
{
for (auto it = NOTIFY_KEYS_VECTOR.cbegin(); it != NOTIFY_KEYS_VECTOR.cend(); it++) {
if (key.compare(*it)) {
notifyTimes++;
break;
}
}
}
const std::vector<std::string> PreferencesObserverCounter::NOTIFY_KEYS_VECTOR = { PreferencesTest::KEY_TEST_INT_ELEMENT,
PreferencesTest::KEY_TEST_LONG_ELEMENT, PreferencesTest::KEY_TEST_FLOAT_ELEMENT,
PreferencesTest::KEY_TEST_BOOL_ELEMENT, PreferencesTest::KEY_TEST_STRING_ELEMENT };
```
Subscribe to data changes and invoke the callback:
``` C++
std::shared_ptr<PreferencesObserver> counter =
std::make_shared<PreferencesObserverCounter>();
pref->RegisterObserver(counter); // Register a callback to return data changes.
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test");
pref->Flush(); // Trigger the onChanged callback of the counter.
EXPECT_EQ(static_cast<PreferencesObserverCounter *>(counter.get())->notifyTimes, 1);
/* same value */
pref->PutInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 2);
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test");
pref->Flush();
EXPECT_EQ(static_cast<PreferencesObserverCounter *>(counter.get())->notifyTimes, 2);
pref->UnRegisterObserver(counter); // Unregister the callback for data changes.
```
7. Delete the specified file.
Delete the **Preferences** singleton of the specified file from the memory, and delete the specified file, its backup file, and damaged files. After the specified files are deleted, the application cannot use that instance to perform any data operation. Otherwise, data inconsistency will occur. The deleted data and files cannot be restored.
``` C++
pref = nullptr;
int ret = PreferencesHelper::DeletePreferences("/data/test/test");
EXPECT_EQ(ret, E_OK);
```
# Lightweight Data Store Overview
The lightweight data store is applicable to access and persistence operations on the data in key-value pairs. When an application accesses a lightweight store instance, the data in the instance will be cached in the memory for faster access. The cached data can also be written back to the text file for persistent storage. Since file read and write consume system resources, you are advised to minimize the frequency of reading and writing persistent files.
## Basic Concepts
- **Key-Value data structure**
A type of data structure. The key is the unique identifier for a piece of data, and the value is the specific data being identified.
- **Non-relational databases**
A database not in compliance with the atomicity, consistency, isolation, and durability (ACID) database management properties of relational data transactions. The data in a non-relational database is independent.
## Working Principles
When an application loads data from a specified Preferences file to a **Preferences** instance, the system stores the instance in the memory through a static container. Each file of an application or process has only one **Preferences** instance in the memory, till the application removes the instance from the memory or deletes the **Preferences** file.
When obtaining a **Preferences** instance, the application can read data from or write data to the instance. The data in the instance can be flushed to its **Preferences** file by calling the **flush()** or **flushSync()** method.
**Figure 1** How lightweight data store works<a name="fig1657785713509"></a>
![](figures/en-us_image_0000001192123772.png)
## Constraints
- **Preferences** instances are loaded to the memory. To minimize non-memory overhead, the number of data records stored in a Preferences instance cannot exceed 10,000. Delete the instances that are no longer used in a timely manner.
- The key in the key-value pairs is of the string type. It cannot be empty or exceed 80 characters.
- If the value in the key-value pairs is of the string type, it can be empty or contain a maximum of 8192 characters.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册