In modern operating systems, data persistence is a critical concern. Especially on mobile and IoT devices, developers are highly focused on how to efficiently, quickly, and securely persist data to disk to ensure application stability and data reliability.
With the continuous evolution of HarmonyOS, its data persistence solutions have become increasingly rich. The commonly used persistence technologies now include MMKV, relational databases, and distributed key-value (KV) storage.
1. MMKV: Lightweight and Efficient Storage
What is MMKV?
MMKV (Memory Mapped Key-Value) is a lightweight and high-performance local data storage solution. It uses memory-mapped files to achieve efficient disk storage. MMKV’s core strengths are efficiency and low memory usage, making it especially suitable for storing small, frequently accessed key-value data.
Using MMKV for Data Persistence
MMKV is available via ohpm
and allows developers to easily persist data to disk. With ArkTS APIs, you can:
- Store simple data types like strings, integers, booleans, etc.
- Support multi-threaded read/write with consistency and thread safety.
- Provide encrypted storage for securing sensitive data.
Advantages of MMKV
- High Performance: Based on memory-mapped file technology, reducing IO frequency and improving speed.
- Ease of Use: ArkTS offers simple APIs for developers to read/write data with ease.
- Encryption Support: Data can be encrypted with minimal configuration to ensure security.
Example Code:
let mmkv = MMKV.defaultMMKV(); mmkv.encodeBool('bool', true); console.info('bool = ', mmkv.decodeBool('bool')); mmkv.encodeInt32('int32', Math.pow(2, 31) - 1); console.info('max int32 = ', mmkv.decodeInt32('int32')); mmkv.encodeInt64('int', BigInt(2**63) - BigInt(1)); console.info('max int64 = ', mmkv.decodeInt64('int')); let str: string = 'Hello OpenHarmony from MMKV'; mmkv.encodeString('string', str); console.info('string = ', mmkv.decodeString('string')); let arrayBuffer: ArrayBuffer = StringToArrayBuffer('Hello OpenHarmony from MMKV with bytes'); mmkv.encodeBytes('bytes', arrayBuffer); let bytes = mmkv.decodeBytes('bytes'); console.info('bytes = ', ArrayBufferToString(bytes)); let arr = new Uint8Array([0, 255, 1, 255]); mmkv.encodeTypedArray('uint8-array', arr); let newUI8Arr = kv.decodeUint8Array('uint8-array'); console.info('uint8-array = ', newUI8Arr);
2. rdbStore
: Relational Database Storage
What is rdbStore?
rdbStore
is a relational database storage solution provided by HarmonyOS. It is based on SQLite and is suited for scenarios that require storage of complex relational data.
For example:
- A class of students with names, student IDs, and grades.
- Company employee records with names, employee IDs, positions, etc.
Since the data is highly structured and relational, it is best stored using a relational database.
Using rdbStore
Before using, you first need to get a store instance:
relationalStore.getRdbStore(this.context, STORE_CONFIG, (err: BusinessError, rdbStore: relationalStore.RdbStore) => { store = rdbStore; if (err) { console.error(`Get RdbStore failed, code is ${err.code}, message is ${err.message}`); return; } console.info('Get RdbStore successfully.'); });
STORE_CONFIG
includes information like the database file name, security level, and whether encryption is enabled.
Once you get the store, you can perform standard CRUD operations (Create, Read, Update, Delete) via its API:
Initialize a Table
async initTable(context: Context, setVersion: boolean = false) { try { let store = await this.getRdbStore(context) if (store.version === 0) { await store.executeSql(this.sqlCreateTable) if (setVersion) store.version = DatabaseConsts.STORE_VERSION } } catch (e){ Logger.error(this.TAG, `Init table ${this.tableName} failed: ${e}`) throw Error(e) } }
Insert Data
async insertData(context: Context, data: ValuesBucket) { try { let store = await this.getRdbStore(context) let res = await store.insert(this.tableName, data) Logger.info(this.TAG, `Insert data completed, ret = ${res}`) } catch (e) { Logger.error(this.TAG, `Insert data failed: ${e}`) throw Error(e) } }
Update Data
async updateData(context: Context, predicate: relationalStore.RdbPredicates, data: ValuesBucket): Promise<number> { return new Promise((resolve, reject) => { this.getRdbStore(context) .then((store) => store.update(data, predicate)) .then((ret) => { Logger.info(this.TAG, `Update data completed, ret = ${ret}`) resolve(ret) }).catch((e: BusinessError) => { Logger.error(this.TAG, `Update data failed, err = ${e}`) reject(e) }); }); }
Delete Data
async deleteData(context: Context, predicate: relationalStore.RdbPredicates): Promise<number> { return new Promise((resolve, reject) => { this.getRdbStore(context) .then((store) => store.delete(predicate)) .then((ret) => { Logger.info(this.TAG, `Delete data completed, ret = ${ret}`) resolve(ret) }).catch((e: BusinessError) => { Logger.error(this.TAG, `Delete data failed, err = ${e}`) reject(e) }); }); }
Query Data
async queryData(context: Context, predicate: relationalStore.RdbPredicates): Promise<relationalStore.ResultSet> { return new Promise((resolve, reject) => { this.getRdbStore(context) .then((store) => store.query(predicate)) .then((result) => { Logger.info(this.TAG, `Query data completed`) resolve(result) }) .catch((e: BusinessError) => { Logger.error(this.TAG, `Query data failed, err = ${e}`) reject(e) }); }); }
Top comments (0)