官方网站后台图片下载怎么做/seo就业指导
1、概述
1.1、功能简介
数据管理为开发者提供数据存储、数据管理能力。
它分为两个部分:
- 数据存储:提供通用数据持久化能力,根据数据特点,分为用户首选项、键值型数据库和关系型数据库。
- 数据管理:提供高效的数据管理能力,包括权限管理、数据备分恢复、数据共享等
注:应用创建的数据库,都保存到应用少盒,当应用卸载时,数据库也会自动删除。
1.2、运作机制
数据管理模块包括用户首选项、键值型数据管理、关系型数据管理、分布式数据对象和跨应用数据管理。
Interface接口层提供标准JS API接口
Frameworks&System service层负责实现部件数据存储功能
另外还有一些SQLite和其它子系统的依赖
- 用户首选项:Preferences, 提供轻量级配置数据持久化能力,支持订阅数据变化的通知能力。不支持分布式同步,常常用来保存应用配置信息、用户偏好设置等
- 键值型数据管理:KV-Store,提供了键值型数据库的读写、加密、手动备份能力。暂不支持分布式功能。
- 关系型数据管理:RelationalStore,提供了关系型数据库的增删改查、加密、手动备份能力。暂不支持分布式功能。
- 分布式数据对象:DataObject,独立提供地象型结构数据的分布式能力,暂不支持分布式功能。
- 跨应用数据管理:DataShare,提供了向其他应用共享以及管理其数据的方法。仅系统应用可用。
2、应用数据持久化概述
应用数据持久化,是指应用将内存中的数据通过文件或数据库的形式保存到设备上。内存中的数据形态通常是任意的数据结构或数据对象,存储介质上的数据形态可能是文本、数据库、二进制文件等。
HarmonyOS标准系统支持典型的存储数据形态有:用户首选项、键值型数据库、关系型数据库
3、用户首选项实现数据持久化
用户首选项为应用提供key-value键值型的数据处理能力,支持应用持久化轻量级数据,并对其进行修改和查询。
Preferences不适合存放过多数据,适用的场景一般为应用保存用户个性化的配置。
3.1、运作机制
用户程序通过JS接口调用用户首选项读写对应的数据文件。开发者可以把用户首选项持久化文件的内容加载到Preferences实例,每个文件唯一对应到一个Preferences实例,系统会通过静态容器把这个实例存储在内存中,直到主动从内存中移除这个实例或删除这个文件。
3.2、使用约束
1、key键为string类型,要求非空且长度不超过80个字节
2、value值为string类型时可以为空,不为空时长度不超过8192个字节
3、内存会随着存储数据量的增大而增大,所以存储的数据应该是轻量级的,建议存储的数据不要超过1万条
3.3、相关接口说明
接口大部分都是异步接口,异步接口都有callback和Promise两种返回形式。以下为callback为例说明
接口名称 | 描述 |
getPreferences(context:Context,name:string,callback:AsyncCallback<Preferences>):void | 获取Preferences 实例 |
put(key:string,value:valueType,callback:AsyncCallback<void>):void | 把数据写入Preferences实例,可以通过flush把实例进行持 久化 |
has(key:string,callback:AsyncCallback<boolean>):void | 检查实例中是否包含指定的key的存储键值对,给定的key不可以为空 |
get(key:string,defValue:valueType,callback:AsyncCallback<valueType>):void | 获取指定键对应的值,如果值为null或者非默认值类型,返回默认数据defValue |
delete(key:string,callback:AsyncCallback<void>):void | 从实例中删除指定key的存储键值对 |
flush(callback:AsyncCallback<void>):void | 把当前实例中的数据异步存储到用户首选项持久化文件中 |
on(type:'change',callback?:Callback<{key:string}>):void | 订阅数据变更,订阅的key的值发生变化,在执行flush方法后,触发callback回调 |
off(type:'change',callback?:Callback<{key:string}>):void | 取消订阅数据变更 |
deletePreferences(context:Context,name:string,callback:AsyncCallback<void>):void | 从内存中移除指定实例,如果这个实例有对应的持久化文件则同时会把持外化文件删除 |
3.4、开发步骤
1、导入用户首选项模块
import dataPreferences from '@ohos.data.preferences';
2、获取Preferences实例,读取指定文件,把数据加载到Preferences实例,用于数据操作
import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
import dataPreferences from '@ohos.data.preferences';export default class EntryAbility extends UIAbility {onCreate(want, launchParam) {}onDestroy() {}onWindowStageCreate(windowStage: window.WindowStage) {// Main window is created, set main page for this abilitytry{dataPreferences.getPreferences(this.context,'mystore',(err,preferences) => {if(err) {console.error(`Failed to get preferences. Code:${err.code},Message:${err.message}`);return;}console.info('Succeeded in getting preferences.')// 进行相关的数据操作})} catch (err) {console.error(`Failed to get preferences. Code:${err.code},Message:${err.message}`);}windowStage.loadContent('pages/Index', (err, data) => {if (err.code) {hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');return;}});}onWindowStageDestroy() {// Main window is destroyed, release UI related resources}onForeground() {// Ability has brought to foreground}onBackground() {// Ability has back to background}
}
在onWindowStageCreate方法中进行读取
3、写入数据
使用put()方法保存数据到缓存的Preferences实例中,在写入数据后如果有必要可以使用flush()方法把Preferences实例的数据存储到持久化文件。
注意:如果键此时已存在则会修改值,如果需要是在键不存在时新增键值对,则需要使用has()进行检查
4、读取数据
使用get()方法获取数据,如果值为null或者非默认值类型,则返回默认数据。
5、删除数据
使用delete()方法删除指定的键值对
6、据的持久化
应用存入数据到Preferences后,可以使用flush()方法实现数据持久化
7、订阅数据更新
使用on(),订阅key值发生变化,flush()执行时,会回调其中的回调方法
8、删除指定文件
使用deletePreferences()方法从内存中移除指定文件对应的Preferences实例,包括内存中的数据。若该Preference存在对应的持久化文件,则同时删除该持久化文件,包括指定文件及其备份文件、损坏文件。
// EntryAbility.tsimport UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
import dataPreferences from '@ohos.data.preferences';export default class EntryAbility extends UIAbility {onCreate(want, launchParam) {}onDestroy() {}onWindowStageCreate(windowStage: window.WindowStage) {// Main window is created, set main page for this abilitytry{dataPreferences.getPreferences(this.context,'mystore',(err,preferences) => {if(err) {console.error(`Failed to get preferences. Code:${err.code},Message:${err.message}`);return;}console.info('Succeeded in getting preferences.')// 进行相关的数据操作globalThis.dataPreferences = preferences;})} catch (err) {console.error(`Failed to get preferences. Code:${err.code},Message:${err.message}`);}windowStage.loadContent('pages/Index', (err, data) => {if (err.code) {hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');return;}});}onWindowStageDestroy() {// Main window is destroyed, release UI related resources}onForeground() {// Ability has brought to foreground}onBackground() {// Ability has back to background}
}
// index.etsimport dataPreferences from '@ohos.data.preferences';
import Prompt from '@system.prompt';
import common from '@ohos.app.ability.common';@Entry
@Component
struct Index {@State message: string = '';@State message1: string = '';dpf:dataPreferences.Preferences = globalThis.dataPreferences;build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold).margin({bottom:10})Text(this.message1).fontSize(50).fontWeight(FontWeight.Bold).margin({bottom:10})Button('put').margin({bottom:15}).onClick(() => {try{this.dpf.has('startup', (err,val) => {if(err) {console.error(`Failed to check data. Code:${err.code}, message:${err.message}`);return;}if (val) {console.info('startup is exists!!')} else {try {this.dpf.put('startup', 'auto', (err) => {if (err) {console.error(`Failed to put data. Code:${err.code}, message:${err.message}`);return;}console.info('succeeded in putting data.')})} catch (err) {console.error(`Failed to put data. Code:${err.code}, message:${err.message}`);}}})}catch(err) {console.error(`Failed to put data. Code:${err.code}, message:${err.message}`);}})Button('get').margin({bottom:15}).onClick(() => {try{this.dpf.get('startup','default',(err,val) => {if(err) {console.error(`Failed to get data. Code:${err.code}, message:${err.message}`);}console.info(`succeeded in getting value of 'startup'. val:${val} `);this.message = val.toString();})}catch (err) {console.error(`Failed to get data. Code:${err.code}, message:${err.message}`);}})Button('delete').margin({bottom:15}).onClick(() => {try{this.dpf.delete('startup', (err) => {if(err) {console.error(`Failed to delete data. Code:${err.code}, message:${err.message}`);return;}console.info('succeeded in deleting the data')})} catch (err) {console.error(`Failed to delete data. Code:${err.code}, message:${err.message}`);}})Button('flush').margin({bottom:15}).onClick(() => {try{this.dpf.flush((err) => {console.error(`Failed to flush data. Code:${err.code}, message:${err.message}`);return;})Prompt.showToast({message: '数据持久化成功!',})} catch (err) {console.error(`Failed to flush data. Code:${err.code}, message:${err.message}`);}})Button('订阅').margin({bottom:15}).onClick(() => {this.dpf.on('change',(key) => {console.info(key + '数据发生变化')})})Button('更新').margin({bottom:15}).onClick(() => {try{this.dpf.put('startup','manual',(err) => {if(err) {console.error(`Failed to put data. Code:${err.code}, message:${err.message}`);return;}})} catch (err){console.error(`Failed to put data. Code:${err.code}, message:${err.message}`);}})Button('deletePreferences').onClick(() => {try{let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;dataPreferences.getPreferences(context,'mystore', (err, val) => {if(err) {console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`);return;}console.info(`successed to delete preferences.`);})} catch (err) {console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`);}})}.width('100%')}.height('100%')}}
4、键值型数据库实现数据持久化
4.1、使用场景介绍
键值型数据库存储键值对形式的数据,一般用来存储的数据没有复杂的关系模型。
4.2、使用约束
1、设备协同数据库,针对每条记录,key的长度小于等于896Byte,value小于4MB
2、单版本数据库,针对每条记录,key的长度小于等于1KB,value小于4MB
3、每个应用程序最多支持同时打开16个键值型分布式数据库
4、键值型数据库事件回调方法不允许进行阻塞操作
4.3、相关接口说明
接口大部分是异步操作,异步接口都有callback和Promise两种形式
接口名称 | 描述 |
createKVManager(config: KVManagerConfig): KVManager | 创建一个KVManager对象实例,用于管数据库对象 |
getKVStore<T>(storeId:string,options:Options,callback:AsyncCallback<T>):void | 指定Options和storeId,创建并得到指定类型的KVStore数据库 |
put(key:string,value:Uint8Array|string|number|boolean,callback:AsyncCallback<void>):void | 添加指定类型的键值对到数据库 |
get(key:string,callback:AsyncCallback<Uint8Array|string|number|boolean>):void | 获取指定键对应的值 |
delete(key:string,callback:AsyncCallback<void>):void | 从数据库中删除指定键值数据 |
4.4、开发步骤
1、获取一个KVManager实例
在EntryAbility.ts中onCreate()或onWindowStageCreate()中创建。
onWindowStageCreate(windowStage: window.WindowStage) {// Main window is created, set main page for this ability// KVManagerConfiglet context = this.context;const KvManagerConfig = {context: context,bundleName: 'com.xiaoxie'};try{let kvManager = distributedKVStore.createKVManager(KvManagerConfig);console.info('Succeeded in create KVManager.')globalThis.kvManager = kvManager;} catch (err){console.error(`Failed to create KVManager, Code:${err.code},Message:${err.Message}`);}windowStage.loadContent('pages/KVStore', (err, data) => {if (err.code) {hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');return;}});}
2、创建并获取键值数据库
3、调用put()方法向键值数据库中插入数据,当我们据时key值存在则会修改其值,否则新增一条数据
4、调用get()方法获取指定键值
5、调用delete()方法删除指定键值的数据
// KVStore.ets
import distributedKVStore from '@ohos.data.distributedKVStore';
import Prompt from '@system.prompt';const options = {createIfMissing: true, // 当数据库文件不存在的时候是否创建,默认创建encrypt: false, // 设置数据库文件是否加密,默认不加密backup: false, // 设置数据库文件是否备份,默认备份kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, // 设置要创建数据库的类型,默认为多设备协同securityLevel: distributedKVStore.SecurityLevel.S2 // 设置数据库的安全级别
};@Entry
@Component
struct KVStore {@State message: string = '';kvManager:distributedKVStore.KVManager = globalThis.kvManagerkvStore:distributedKVStore.SingleKVStore = undefined;build() {Row() {Column() {Text(this.message).fontSize(20).fontWeight(FontWeight.Bold).margin({bottom:10})Button('1、创建并获取键值数据库').width('50%').margin({bottom:10}).onClick(() => {try{this.kvManager.getKVStore('storeId',options,(err,kvStore:distributedKVStore.SingleKVStore) => {if(err) {console.error(`Failed to get KVStore, Code:${err.code},Message:${err.message}`);return;}Prompt.showToast({message: '获取键值数据库成功!',duration: 1500})this.kvStore = kvStore;});} catch (e) {console.error(`Failed to get KVStore, Code:${e.code},Message:${e.message}`);}})Button('2、向键值数据库插入数据').width('50%').margin({bottom: 10}).onClick(() => {try{if(this.kvStore) {this.kvStore.put('test_key','test_value',(err) => {if(err) {console.error(`Failed to put data, Code:${err.code},Message:${err.message}`);return;}Prompt.showToast({message: '向键值数据加中插入数据成功!',duration: 1500})})} else {Prompt.showToast({message: '错误:请先获取数据库!',duration: 1500})}} catch (e) {console.error(`Failed to put data, Code:${e.code},Message:${e.message}`);}})Button('3、获取指定键的值').width('50%').margin({bottom:10}).onClick(() => {try{if(this.kvStore) {this.kvStore.get('test_key',(err,data) => {if(err) {this.message = '';console.error(`Failed to get data, Code:${err.code},Message:${err.message}`);return;}this.message = '';this.message = data.toString();})} else {Prompt.showToast({message: '错误:请先获取数据库!',duration: 1500})}} catch (e) {console.error(`Failed to get data, Code:${e.code},Message:${e.message}`);}})Button('4、删除指定键值数据').width('50%').onClick(() => {try{if(this.kvStore) {this.kvStore.delete('test_key',(err) => {if(err) {console.error(`Failed to delete data, Code:${err.code},Message:${err.message}`);return;}Prompt.showToast({message: '删除指定键值数据成功!',duration: 1500})})} else {Prompt.showToast({message: '错误:请先获取数据库!',duration: 1500})}} catch (e){console.error(`Failed to delete data, Code:${e.code},Message:${e.message}`);}})}.width('100%')}.height('100%')}
}
5、关系型数据库实现数据持久化
5.1、使用场景介绍
关系型数据库基于SQLite组件,适用于存储包含复杂关系数据的场景。
5.2、相关术语介绍
1、谓词:数据库中用来代表数据实体的性质、特征或数据实体之间关系的词项,它主要用来定义数据库的操作条件。
2、结果集:指的是用户查询后的结果集合。
5.3、动作机制
关系型数据库对应用提供通用的操作接口,底层使用SQLite作为持久化存储引擎。
5.4、约束限制
1、系统默认日志方式是WAL(Write Ahead Log)模式,默认落盘方式是FULL模式
2、连接池最大个数是4个
3、数据库同一时间只能支持一个写操作
4、当应用被卸载完成后,设备上的相关数据库文件及临时文件会被自动清除
5.5、相关接口说明
大部分为异步接口,异步接口都有callback和Promise两种形式
接口说明 | 描述 |
getRdbStore(context: Context, config: StoreConfig, callback:AsyncCallback<RdbStore>): void | 获得一个RdbStore,操作关系型数据库,用户可以根据自己的需求配置RdbStore的参数,然后通过RdbStore调用相关接口来执行相关的数据操作 |
executeSql(sql: string, bindArgs:Array<ValueType>,callback:AsyncCallback<void>): void | 执行包含指定参数但是不返回值的sql语句 |
inser(table:string,values:valuesBucket,callback:AsyncCallback<number>): void | 向表中插入一行数据 |
update(values:ValuesBucket,predicates:RdbPredicates,callback:AsyncCallback<number>): void | 根据RdbPredicates的指定实例对象更新数据库中数据 |
delete(predicates:RdbPredicates,callback:AsyncCallback<number>):void | 根据RdbPredicates的指定实例对象删除数据库中数据 |
query(predicates:RdbPredicates,columns:Array<string>,callback:AsyncCallback<ResultSet>):void | 根据指定条件查询数据库中的数据 |
deleteRdbStore(context:Context,name:string,callback:AsyncCallback<void>):void | 删除数据库 |
5.6、开发步骤
1、获取一个RdbStore
在EntryAbility.ts文件件的onCreate()或onWindowStageCreate()方法中创建数据库获取到RdbStore对象并绑定到globalThis,便于后续使用。
// EntryAbility.ts
onWindowStageCreate(windowStage: window.WindowStage) {// RdbStoreconst STORE_CONFIG = {name: 'RdbTest.db', // 数据库名称securityLevel: relationalStore.SecurityLevel.S1 // 数据库的安全级别};relationalStore.getRdbStore(this.context, STORE_CONFIG, (err,store) => {if(err) {console.error(`Failed to create rdbstore. Code:${err.code},Message:${err.message}`);return;}console.info('Succeeded in create RdbStore.')globalThis.rdbStore = store;})
}
2、创建数据表,定义好建表语句,执行executeSql()方法
3、调用insert()方法来插入数据
注意:关系型数据库没有显式的flush操作实现持久化,数据插入即保存在持久化文件
4、根据谓词指定的实例对象,对数据进行修改或删除
5、根据谓词指定的查询条件查找数据,调用query()方法查找数据,会返回一个ResultSet结果集,当应用完成查询数据操作,不再使用ResultSet时,及时调用close方法关闭结查集,释放内存空间。
5、删除数据库,调用deleteRdbStore()方法,用来删除数据库及数据库相关的文件
import relationalStore from '@ohos.data.relationalStore'
import Prompt from '@system.prompt';
import common from '@ohos.app.ability.common';@Entry
@Component
struct RdbStore {@State message: string = ''rdbStore: relationalStore.RdbStore = globalThis.rdbStore;build() {Row() {Column() {Text(this.message).fontSize(20).fontWeight(FontWeight.Bold).margin({bottom:10})Button('创建数据表').width('50%').margin({bottom:10}).onClick(() => {try {// 数据库建表语句let SQL_CREATE_TABLE: string = 'create table if not exists employee(id integer primary key autoincrement, name text not null, age integer, salary real, codes blob)';this.rdbStore.executeSql(SQL_CREATE_TABLE); // 执行sql语句,创建数据表Prompt.showToast({message: '创建数据表成功',duration: 1500})} catch (err) {console.error(`创建数据表失败,Code:${err.code},Message:${err.Message}`);}})Button('向数据表中插入数据').width('50%').margin({bottom:10}).onClick(() => {let valueBucket = {'name': '张三','age': 18,'salary': 20000.00,'codes' : new Uint8Array([1,2,3,4,5])};this.rdbStore.insert('employee',valueBucket,(err,rowId) => {if(err) {console.error(`Failed to insert data. Code:${err.code},Message:${err.message}}`);return;}Prompt.showToast({message: `插入数据成功,插入数据id:${rowId}`,duration: 2000})})})Button('修改数据表中指定数据').width('50%').margin({bottom:10}).onClick(() => {let valueBucket = {'name': '李四','age': 18,'salary': 20000.00,'codes' : new Uint8Array([1,2,3,4,5])};let predicates = new relationalStore.RdbPredicates('employee'); // 创建表employee的predicatespredicates.equalTo('name','张三'); // 匹配employee中name为张三的字段this.rdbStore.update(valueBucket,predicates,(err,rows) => {if(err) {console.error(`Failed to update data. Code:${err.code},Message:${err.message}}`);return;}Prompt.showToast({message: `修改数据成功,修改影响记录行数:${rows}`,duration: 2000})})})Button('删除数据表中指定数据').width('50%').margin({bottom:10}).onClick(() => {let predicates = new relationalStore.RdbPredicates('employee');predicates.equalTo('name','李四');this.rdbStore.delete(predicates, (err,rows) => {if(err) {console.error(`Failed to delete data. Code:${err.code},Message:${err.message}}`);return;}Prompt.showToast({message: `删除数据成功,删除影响记录行数:${rows}`,duration: 2000})})})Button('查询数据').width('50%').margin({bottom:10}).onClick(() => {this.message = '';let predicates = new relationalStore.RdbPredicates('employee');predicates.equalTo('name','张三');this.rdbStore.query(predicates,['id','name','age','salary','codes'],(err,resultSet) => {if(err) {this.message = '';console.error(`Failed to query data. Code:${err.code}, message:${err.message}`);return;}// this.message = resultSet.columnNames.join('|')if(resultSet.rowCount > 0 ){resultSet.goToFirstRow();this.message = resultSet.getString(resultSet.getColumnIndex('name')) + ' - ' + resultSet.getDouble(resultSet.getColumnIndex('salary'));}resultSet.close();})})Button('删除数据库及相关文件').width('50%').onClick(() => {let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;relationalStore.deleteRdbStore(context,'RdbTest.db',(err) => {if(err) {console.error(`Failed to delete RdbStore. Code:${err.code}, message:${err.message}`);return;}Prompt.showToast({message: '删除数据库成功!',duration: 1500})})})}.width('100%')}.height('100%')}
}
6、数据可靠性与安全性
6.1、功能场景说明
在系统运行中,存储损坏、存储空间不足、文件系统权限、系统掉电等等都可能导致数据库发生故障。为此数据管理提供了数据可靠与安全性相关的解决方案和保障。
- 备份、恢复功能:重要业务数据丢失出息严重异常场景,可以通过备份恢复数据库,保障数据不丢失
- 数据库加密功能:当数据库中存储一些敏感信息时,可以对数据库进行加密,提高数据的安全性
- 数据库分类分级:提供基于数据安全标签和设备安全等级进行访问控制的能力,保证数据安
另: 备份数据库存储在应用的沙箱中,当存储空间不足时,可以选择删除本地的数据库备份,释放空间。
6.2、基本概念
6.2.1、数据库备份与恢复
- 数据库备份:对当前数据库的数据库文件进行完整备份,在做备份时不用关闭数据库,直接调用对应的备份接口就可以了
- 数据库恢复:从指定的备份文件恢复到当前数据库文件。恢复完后,当前数据库数据保持与指定备份文件一致
6.2.2、数据库加密
加密是对整个数据库文件的加密,可以增强数据库的安全性,有效保护数据库内容
6.2.3、数据库分类分级
分布式数据管理对数据实施分类分级保护,提供基于数据安全标签以及设备安全等级的访问控制机制。数据安全标签和设备安全等级越高,加密措施和访问控制措施越严格,数据安全性越高。
6.3、运作机制
6.3.1、数据库备份与恢复机制
数据库在备份时,会把当前数据库备份在指定的文件件中,后续对数据库的操作不会影响备份的数据库文件,只有当恢复指定的数据库文件时,才会把备份的数据库文件件覆盖当前数据库,实现回滚。
键值型数据库备份路径:/data/service/el1(el2)/public/database/...{appId}/kvdb/backup/...{storeId}
关系型数据库备份路径:/data/app/el1(el2)/100/database/...{bundlename}/rdb
6.3.2、数据库加密机制
在数据库加密时,开发者无需传入密钥,只需要设置数据库加密的状态即可。系统会自动帮助开发者把数据库加密。使用huks通用密钥库系统。
6.4、相关约束限制
数据库加密密钥一年自动更换一次
键值型数据库最多可以备份5份
键值型数据库的自动备份需要在熄屏且充电的状态下进行
6.5、数据库备份与恢复
键值型数据库和关系型数据库都支持数据库的备份与恢复。同时键值型数据库还可以删除数据库备份,以释放本地存储空间。
6.5.1、键值型数据库的备份、恢复及删除
键值型数据库,通过backup接口实现数据库备份,通过restore接口实现数据库恢复,通过deletebackup接口删除数据库备份。
import distributedKVStore from '@ohos.data.distributedKVStore';
import Prompt from '@system.prompt';
const options = {createIfMissing: true,encrypt: false,backup: false,kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,securityLevel: distributedKVStore.SecurityLevel.S2
};@Entry
@Component
struct KVStoreBack {@State message: string = '';kvManager: distributedKVStore.KVManager = globalThis.kvManager;kvStore: distributedKVStore.SingleKVStore;build() {Row() {Column() {Text(this.message).fontSize(20).fontWeight(FontWeight.Bold).margin({bottom:10})Button('1.创建并获取键值数据库').width('50%').margin({bottom:10}).onClick(() => {let kvStorePromise = this.kvManager.getKVStore("myStore",options);kvStorePromise.then((store: distributedKVStore.SingleKVStore) => {this.kvStore = store;}).catch((err) => {console.error(`创建并获取键值数据库失败, 失败代码:${err.code}, 失败原因:${err.message}`);return;})})Button('2.键值数据库插入数据').width('50%').margin({bottom:10}).onClick(() => {try {this.kvStore.put('name', 'xiaoxie', (err) => {if (err) {console.error(`存储数据失败, 失败代码:${err.code}, 失败原因:${err.message}`);return;}Prompt.showToast({message: '存储数据成功!!',duration: 1500})this.message = 'xiaoxie'; // 添加数据成功把message赋值为写入的值})} catch (e) {console.error(`存储数据失败, 失败代码:${e.code}, 失败原因:${e.message}`);}})Button('3.备份数据').width('50%').margin({bottom:10}).onClick(() => {try{let file = 'bk001';this.kvStore.backup(file, (err) => {if(err) {console.error(`备份数据失败, 失败代码:${err.code}, 失败原因:${err.message}`);} else {Prompt.showToast({message: `备份数据成功,备份文件:${file}`,duration: 1500})}})} catch (e) {console.error(`备份数据失败, 失败代码:${e.code}, 失败原因:${e.message}`);}})Button('4.删除数据').width('50%').margin({bottom:10}).onClick(() => {try{this.kvStore.delete('name',(err) => {if(err) {console.error(`删除数据失败, 失败代码:${err.code}, 失败原因:${err.message}`);return;}Prompt.showToast({message: '删除数据成功!',duration: 1500})this.message = ''; // 删除数据成功后把message置空})} catch (e) {console.error(`删除数据失败, 失败代码:${e.code}, 失败原因:${e.message}`);}})Button('5.恢复数据').width('50%').margin({bottom:10}).onClick(() => {this.message = ''try{this.kvStore.restore('bk001',(err) => {if(err) {console.error(`删除数据失败, 失败代码:${err.code}, 失败原因:${err.message}`);} else {try{this.kvStore.get('name',(err,data) => {if(err) {console.error(`获取数据失败, 失败代码:${err.code}, 失败原因:${err.message}`);return;}this.message = data.toString(); // 恢复数据后把message的值赋为恢复后的值})} catch (e) {console.error(`获取数据失败, 失败代码:${err.code}, 失败原因:${err.message}`);}}})} catch (e) {console.error(`恢复数据失败, 失败代码:${e.code}, 失败原因:${e.message}`);}})Button('6、删除备份').width('50%').onClick(() => {let files = ['bk001'];try{this.kvStore.deleteBatch(files).then((data) => {Prompt.showToast({message: `删除备份成功,文件:${data[0]},结果:${data[1]}`,})}).catch((err) => {console.error(`删除备份失败, 失败代码:${err.code}, 失败原因:${err.message}`);})} catch (e) {console.error(`删除备份失败, 失败代码:${e.code}, 失败原因:${e.message}`);}})}.width('100%')}.height('100%')}
}
6.5.2、关系型数据库备份与恢复
关系型数据库,通过backup接口实现数据库备份,通过restore接口实现数据库恢复。
import relationalStore from '@ohos.data.relationalStore';
import Prompt from '@system.prompt';
const SQL_CREATE_TABLE: string = 'create table if not exists employee(id integer primary key autoincrement, name text not null, age integer, salary real, codes blob)';@Entry
@Component
struct RdbStroeBack {@State message: string = '';rdbStore: relationalStore.RdbStore = globalThis.rdbStore;build() {Row() {Column() {Text(this.message).fontSize(20).fontWeight(FontWeight.Bold).margin({bottom:10})Button('1.创建数据表').width('50%').margin({bottom:10}).onClick(() => {try{this.rdbStore.executeSql(SQL_CREATE_TABLE);Prompt.showToast({message:'创建数据表成功',duration:1500})} catch (e){console.error(`创建数据表失败!Code:${e.code},Message:${e.message}`);}})Button('2.向数据表插入数据').margin({bottom:10}).width('50%').onClick(() => {let valueBucket = {'name': '赵子龙','age': 20,'salary': 100.5,'codes': new Uint8Array([1,2,3,4,5])};this.rdbStore.insert('employee',valueBucket).then((rowId) => {Prompt.showToast({message: '插入数据成功!',duration: 1500})this.message = `${rowId} - ${valueBucket.name} - ${valueBucket.salary}`}).catch((err) => {console.error(`插入数据失败!Code:${err.code},Message:${err.message}`);})})Button('3.备份数据库').margin({bottom:10}).width('50%').onClick(() => {this.rdbStore.backup('dbBackup.db',(err) => {if(err) {console.error(`备份数据库失败!Code:${err.code},Message:${err.message}`);return;}Prompt.showToast({message: '备份数据库成功!',duration: 1500})})})Button('4.删除数据').width('50%').margin({bottom:10}).onClick(() => {let predicates = new relationalStore.RdbPredicates('employee');predicates.equalTo('name','赵子龙');this.rdbStore.delete(predicates).then((rows) => {if(rows > 0) {this.message = ''; // 删除后清空界面展示信息}}).catch((e) => {console.error(`删除指定数据失败!Code:${e.code},Message:${e.message}`);})})Button('5.恢复数据').width('50%').onClick(() => {this.rdbStore.restore('dbBackup.db',(err) => {if(err) {console.error(`恢复数据失败. Code:${err.code},message:${err.message}`);} else {let predicates = new relationalStore.RdbPredicates('employee');predicates.equalTo('name','赵子龙');this.rdbStore.query(predicates,['id','name','salary'],(err,resultSet) => {if(err) {console.error(`查询数据失败. Code:${err.code},message:${err.message}`);} else {if(resultSet.rowCount > 0) {resultSet.goToFirstRow();this.message = resultSet.getLong(resultSet.getColumnIndex('id')) + ' - '+ resultSet.getString(resultSet.getColumnIndex('name')) + ' - '+ resultSet.getDouble(resultSet.getColumnIndex('salary'));}}})}})})}.width('100%')}.height('100%')}
}
6.6、数据库加密
6.6.1、使用场景
为了增强数据库的安全性,数据库提供了一个安全适用的数据库加密能力,从而对数据库存储的内容实施有效保护。通过数据库加密等安全方法实现了数据库数据存储的保密性和完整性要求,使得数据库以密文方式存储并在密态方式下工作,确保了数据安全。
注意:加密后的数据库只能通过接口进行访问,无法通过其它的方式来打开数据库文件。数据库加密的属性在创建数据库时确认,无法变更。
键值型数据库和关系型数据库都直接数据加密操作
6.6.2、键值型数据库加密
通过options中encrypt参数来控制是否加密,默认是false,表示不加密,当这个参数为true时则表示加密处理。
import distributedKVStore from '@ohos.data.distributedKVStore'
import Prompt from '@system.prompt';const options = {createIfMissing: true,encrypt: true, // 数据库加密backup: false,kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,securityLevel: distributedKVStore.SecurityLevel.S2
};@Entry
@Component
struct KVStoreEncrypt {@State message: string = ''kvManager:distributedKVStore.KVManager = globalThis.kvManager;kvStore: distributedKVStore.SingleKVStore;build() {Row() {Column() {Text(this.message).fontSize(20).fontWeight(FontWeight.Bold).margin({bottom:10})Button('创建加密数据库').width('50%').margin({bottom:10}).onClick(() => {this.kvManager.getKVStore('ms1',options,(err,store:distributedKVStore.SingleKVStore) => {if(err) {console.error(`创建加密数据库失败!,代码:${err.code},原因:${err.message}`);return;}this.kvStore = store;Prompt.showToast({message: `创建加密数据库成功!`,duration: 2000})})})}.width('100%')}.height('100%')}
}
其中kvManager对象还是在EntryAbility.ts的onCreate或onWindowStageCreate中创建的
// KVManagerConfiglet context = this.context;const KvManagerConfig = {context: context,bundleName: 'com.xiaoxie'};try{let kvManager = distributedKVStore.createKVManager(KvManagerConfig);console.info('Succeeded in create KVManager.')globalThis.kvManager = kvManager;} catch (err){console.error(`Failed to create KVManager, Code:${err.code},Message:${err.Message}`);}
6.6.3、关系型数据库加密
关系型数据库,过在创建relationalStore.RdbStore时给定的config参数中指定encrypt:true即可。
这个参数默认是false的
// RdbStoreconst STORE_CONFIG = {name: 'RdbTest.db', // 数据库名称securityLevel: relationalStore.SecurityLevel.S1 // 数据库的安全级别};relationalStore.getRdbStore(this.context, STORE_CONFIG, (err,store) => {if(err) {console.error(`Failed to create rdbstore. Code:${err.code},Message:${err.message}`);return;}console.info('Succeeded in create RdbStore.')globalThis.rdbStore = store;})
相关文章:

HarmonyOS开发(九):数据管理
1、概述 1.1、功能简介 数据管理为开发者提供数据存储、数据管理能力。 它分为两个部分: 数据存储:提供通用数据持久化能力,根据数据特点,分为用户首选项、键值型数据库和关系型数据库。数据管理:提供高效的数据管…...

acwing-Linux学习笔记
acwing-Linux课上的笔记 acwing-Linux网址 文章目录 1.1常用文件管理命令homework作业测评命令 2.1 简单的介绍tmux与vimvimhomeworktmux教程vim教程homework中的一些操作 3 shell语法概论注释变量默认变量数组expr命令read命令echo命令printf命令test命令与判断符号[]逻辑运算…...

Python渗透测试——一、数据包的编辑工具——Scapy
Python渗透测试 一、Scapy简介二、Scapy中的分层结构三、Scapy中的常用函数四、在Scapy 中发送和接收数据包五、Scapy 中的抓包函数 一、Scapy简介 提到数据包(这里泛指帧、段和报文等)的构造,我们首先需要了解协议和分层这两个概念。在“互联世界的规则一协议”中…...

使用webstrom编写vue开启提示
1.语言服务器选择 2.文件类型–忽略的文件和文件夹,删去,node_modules,就可以点进去库了 3.禁用JSLint、TSLint 4.开启node辅助 5.如果是vite,开启自动读取,或手动指定 6.如果是Webpack,开启自动读取&#…...

linux远程桌面管理工具(xrdp)、向日葵
Windows远程桌面 linux远程桌面 使用向日葵远程桌面(手机端同理) Windows远程桌面 微软自带Remote Desktop Connection Manager (RDCMan)远程控制管理软件介绍 远程桌面连接管理器 v2.93 linux远程桌面 Windows远程桌面Ubunt…...

【力扣100】8.找到字符串中所有字母异位词
添加链接描述 class Solution:def findAnagrams(self, s: str, p: str) -> List[int]:sildingstrresult[]p.join(sorted(p))for i in range(len(s)):if len(sildingstr)<len(p):sildingstrsildingstrs[i]# print(sildingstr)if len(sildingstr)len(p):sort_sildingstr.j…...

圆通速递查询,圆通速递单号查询,用表格导出查询好的物流信息
批量查询圆通速递单号的物流信息,以表格的形式导出查询好的物流信息。 所需工具: 一个【快递批量查询高手】软件 圆通速递单号若干 操作步骤: 步骤1:运行【快递批量查询高手】软件,并登录 步骤2:点击主界…...

FLStudio中文2024中文最新汉化安装包下载
FLStudio中文21最新版本以其使用速度而闻名,是一个高度复杂的音乐制作环境。FL Studio免费,联合国音序器音频和MIDI每个复合编辑都是音乐。现代的DAW是一种非凡的野兽。首先,它在很大程度上把自己放在了(几乎)每个人记录过程的核心。其次&…...

AI:大语言模型训练方法 - 机器学习
Transformer Transformer是一种深度学习的模型架构,特别适用于自然语言处理任务。Transformer 模型的核心创新在于其 "自注意力"(Self-Attention)机制,这种机制使得模型可以有效地捕捉输入数据中的长距离依赖关系。 T…...

Linux(17):认识与分析登录档
什么是登录档 【详细而确实的分析以及备份系统的登录文件】是一个系统管理员应该要进行的任务之一。 登录档 就是记录系统活动信息的几个文件,例如:何时、何地(来源IP)、何人(什么服务名称)、做了什么动作(讯息登录啰)。 换句话说就是:记录系…...

STM32上模拟CH340芯片的功能 (一)
#虚拟串口模拟CH340# 代码gitee地址:STM32F103_CH340: 用STM32模拟ch340USB串口的功能 一、思路 1. 确定通信接口:CH340是一款USB转串口芯片,因此您需要选择STM32上的某个USB接口来实现USB通信。通常情况下,STM32系列芯片都有内…...

图论——最小生成树
图论——最小生成树 A wise man changes his mind, a fool never will 生成树 一个连通图的生成树是一个极小的连通子图,它包含图中全部的n个顶点,但只有构成一棵树的n-1条边。 最小生成树 在这些边中选择N-1条出来,连接所有的N个点。这N-1…...

C++基础 -42- STL库之list链表
———————STL库之list链表——————— 🎄 list链表的格式(需要定义头文件) list<int> data1(4, 100);list<int> data2(4, 500);🎄list链表的合并接口 🎄举例使用合并接口并且验证 data2.merge(data1);list<int>::…...

Backend - Python 序列化
目录 一、作用1:代码块存入数据库 二、作用2:前后端传递数据 (一)前端 1. JSON.stringify() 2. JSON.parse() (二)后端 1. json.dumps() (1)作用 (2)…...

初级数据结构(一)——顺序表
文中代码源文件已上传:数据结构源码 <-上一篇 NULL | 初级数据结构(二)——链表 下一篇-> 1、顺序表的特点 1.1、数组 现实中数据记录一般都记录在表格中,如进货单、菜单等,它们的最大特点就是…...

实现:切换页面切换标题,扩展 vue-router 的类型
布局容器-页面标题 网址:https://router.vuejs.org/zh/guide/advanced/meta 给每一个路由添加 元信息 数据 router/index.ts const router createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{ path: /login, component: () > im…...

已通过考试和认证注册以及后续计划表
已通过考试和认证注册以及后续计划表 软考 - 计算机技术与软件专业技术资格(水平)考试信息系统集成及服务项目管理人员工程类考试计划你关注的证书样子 软考 - 计算机技术与软件专业技术资格(水平)考试 高级 信息系统项目管理师&…...

开源计算机视觉库OpenCV详解
目录 1、概述 2、OpenCV详细介绍 2.1、OpenCV的起源 2.2、OpenCV开发语言 2.3、OpenCV的应用领域 3、OpenCV模块划分 4、OpenCV源码文件结构 4.1、根目录介绍 4.2、常用模块介绍 4.3、CUDA加速模块 5、OpenCV配置以及Visual Studio使用OpenCV 6、关于Lena图片 7、…...

使用pytorch查看中间层特征矩阵以及卷积核参数
这篇是我对哔哩哔哩up主 霹雳吧啦Wz 的视频的文字版学习笔记 感谢他对知识的分享 1和4是之前讲过的alexnet和resnet模型 2是分析中间层特征矩阵的脚本 3是查看卷积核参数的脚本 1设置预处理方法 和图像训练的时候用的预处理方法保持一致 2实例化模型 3载入之前的模型参数 4载入…...

HarmonyOS4.0从零开始的开发教程09页签切换
HarmonyOS(七)页签切换 List组件和Grid组件的使用 Tabs组件的使用 概述 在我们常用的应用中,经常会有视图内容切换的场景,来展示更加丰富的内容。比如下面这个页面,点击底部的页签的选项,可以实现“首页…...

大电流H桥电机驱动电路的设计与解析(包括自举电路的讲解,以IR2104+LR7843为例)
大电流H桥电机驱动电路的设计与解析(包括自举电路的讲解,以IR2104LR7843为例) 电机驱动板主要采用两种驱动芯片,一种是全桥驱动(如:HIP4082),一种是半桥驱动(如ÿ…...

windows11 windows 11 (win11 win 11) 怎么安装 Python3 ? numpy? sounddevice? 声音信号处理库?
首先确认要安装的 sounddevice 库,链接:https://python-sounddevice.readthedocs.io/en/0.4.6/ 根据文档,可知最新的 sounddevice 版本是 0.4.6 进入安装页面查看,发现 Newest sounddevice 可以使用 pip 安装,如下图…...

git如何配置多个远程仓库,并且进行切换
一、配置多个远程仓库并进行切换,请按照以下步骤进行操作: 打开命令行终端,并进入您的 Git 仓库所在的目录。添加第一个远程仓库,使用以下命令:git remote add origin <第一个远程仓库的 URL>这里将远程仓库命名…...

计算机存储单位 + 程序编译过程
C语言的编译过程 计算机存储单位 头文件包含的两种方式 使用 C/C 程序常用的IDE 常用的C语言编译器: 在选择编译器时,需考虑平台兼容性、性能优化、调试工具和开发人员的个人偏好等因素。 详细教程可转 爱编程的大丙...

vue路由导航守卫(全局守卫、路由独享守卫、组件内守卫)
目录 一、什么是Vue路由导航守卫? 二、全局守卫 1、beforeEach 下面是一个beforeEach的示例代码: 2、beforeResolve 下面是一个beforeResolve的示例代码: 3、afterEach 下面是一个afterEach的示例代码: 三、路由独享守卫…...

单片机双机通信控制跑马灯
实验要求 两个单片机各驱动8个LED灯,构成两个跑马灯,要求甲单片机LED的点亮方式是从上至下,首先是最上面第一个点亮、其次是前两个点亮、其次是前三个点亮……直至8个灯全部点亮,8个灯全部灭,重复这个过程,…...

微信小程序:button微信开放能力打开客服会话分享到聊天框
文档 https://developers.weixin.qq.com/miniprogram/dev/component/button.html 打开客服会话 按钮关键属性 open-type"contact"功能按钮 <button class"mo-open-type"open-type"contact"> </button>分享 <button class&q…...

【数据结构】——队列实现二叉树的功能
前言:二叉树的实现方式多种多样,有数组实现满二叉树,有链表实现完全二叉树,今天我们就用队列来实现二叉树。 创建二叉树: typedef int BTDataType; typedef struct BinaryTreeNode {BTDataType data;struct BinaryTre…...

【已解决】Win7虚拟机安装VMtools报错
在做以前的实验的时候发现要用到Win7虚拟机,于是就安装了一个Win7的虚拟机,但是发现屏幕太小,而且来回复制文本、复制文件太不方便了,索性就安装了VMtools,发现还安装不成– 情况1 报错:本程序需要您将此…...

华为OD机试真题-小明找位置-2023年OD统一考试(C卷)
题目描述: 小朋友出操,按学号从小到大排成一列;小明来迟了,请你给小明出个主意,让他尽快找到他应该排的位置。 算法复杂度要求不高于nLog(n);学号为整数类型,队列规模<10000; 输…...