目录

缓存和客户端数据存储体系Ark-Data-Kit-应用数据持久化首选项持久化K-V关系型数据库持续更新中...

缓存和客户端数据存储体系(Ark Data Kit)— 应用数据持久化(首选项持久化、K-V、关系型数据库)持续更新中…

Core File Kit做怎删改查操作不便,用Ark Data Kit。

功能介绍

ArkData (方舟数据管理)为开发者提供数据存储、数据管理和数据同步能力,比如联系人应用数据可以保存到数据库中,提供数据库的安全、可靠以及共享访问等管理机制,也支持与手表同步联系人信息。

  • 标准化数据定义:提供HarmonyOS跨应用、跨设备的统一数据类型标准,包含标准化数据类型和标准化数据结构。

  • 数据存储:提供通用数据持久化能力,根据数据特点,分为用户首选项、键值型数据库和关系型数据库。

  • 数据管理:提供高效的数据管理能力,包括权限管理、数据备份恢复、数据共享框架等。

  • 数据同步:提供跨设备数据同步能力,比如分布式对象支持内存对象跨设备共享能力,分布式数据库支持跨设备数据库访问能力。

应用创建的数据库,都保存到应用沙盒,当应用卸载时,数据库也会自动删除。

概述:

ArkData Kit(方舟数据管理)为开发者提供数据存储、数据管理和数据同步能力,比如联系人数据可以保存到数据库中,提供数据库的安全、可靠以及共享访问等管理机制,也支持与手表同步联系人信息。

https://i-blog.csdnimg.cn/direct/901bf85ba2a04496b542d879d70f15d3.jpeg应用数据持久化(三种方式) 应用数据持久化,是指应用将内存中的数据通过 文件或数据库 的形式保存到设备上。内存中的数据形态通常是任意的数据结构或数据对象,存储介质上的数据形态可能是文本、数据库、二进制文件等。HarmonyOS标准系统支持典型存储数据形态包括如下三类:

用户首选项(Preferences) :通常用于 __保存应用的配置信息__ 。数据通过文本 的形式保存在设备中,应用使用过程中会将文本中的数据 全量加载 到内存中,所以访问速度快、效率高,但不适合需要存储大量数据的场景。

https://i-blog.csdnimg.cn/direct/fd0e5d07c8ec43e588661a3ed96266b3.png,选项都是唯一的,都是首选项。 应用于应用的各种设置。

键值型数据库(KV-Store ):一种 非关系数据库(KV),其数据以“键值 ”对的形式进行组织、索引和存储,其中“键”作为唯一标识符。适合很少数据关系和业务关系的业务数据存储,尤其是分布式应用场景中。

(如:批量同种类型的数据,10月1号进账多少钱,10-1出账多少钱,10-2进出账多少钱,。。。很规律的数据)

关系型数据库(RelationalStore) :一种 关系型 数据库(Table),以行和列(表格) 的形式存储数据,广泛用于应用中的关系型数据的处理,包括一系列的增、删、改、查等接口,开发者也可以运行自己定义的SQL语句来满足复杂业务场景的需要。

(如我的联系人、收货地址、收货明细)

一、用户首选项

1、向首选项对象写出KV数据

let p = preferences.getPreferencesSync(getContext() , { name: ‘myData01’ // 首选项文件的名称 } )

为什么得到首选项,要获取上下文呢? 通过上下文能找到文件的沙箱目录,通过沙箱目录才能找到文件存到哪去。 因为首选项是一个全局的对象,所以需要获取上下文来获取首选项对象。

用户首选项持久化数据都是Key-Value 对;Key非空且唯一 ,长度不能超过80个字节;Value允许为空 ,如果是字符串类型,必须采用UTF-8编码,长度不能超过8192个字节。 // 2、向首选项对象写出KV数据 p.putSync(“myBGColor”, ‘#f00’) p.putSync(“autoStart”, true) p.putSync(“myBGColor”, ‘#0f0’) p.putSync(“autoStart”, 100)

// 3、刷新首选项对象

// 3、刷新首选项对象 p.flushSync() // 刷新后,才能看到数据,把内存中的修改持久化到文件中

// 刷新后,才能看到数据,把内存中的修改持久化到文件中 完整代码: Button(‘1、向首选项对象写出KV数据’) .onClick(()=>{ // 1、先找到首选项对象 let p = preferences.getPreferencesSync(getContext() , { name: ‘myData01’ // 首选项文件的名称 } ) /* 为什么得到首选项,要获取上下文呢? 通过上下文能找到文件的沙箱目录,通过沙箱目录才能找到文件存到哪去。 因为首选项是一个全局的对象,所以需要获取上下文来获取首选项对象 */ // 2、向首选项对象写出KV数据 p.putSync(“myBGColor”, ‘#f00’) p.putSync(“autoStart”, true) p.putSync(“myBGColor”, ‘#0f0’) p.putSync(“autoStart”, 100) // 3、刷新首选项对象 p.flushSync() // 刷新后,才能看到数据,把内存中的修改持久化到文件中 ctx.preferenceDir() console.log(’—首选项数据写出完毕—’) })

效果:

https://i-blog.csdnimg.cn/direct/ad3ac3b246524335a7871ec90df8801d.pnghttps://i-blog.csdnimg.cn/direct/d5ab5cff2c874dd7bb81522cdf9f3a50.png

2、向首选项对象读取KV数据

// 1、先找到首选项对象 let p = preferences.getPreferencesSync(getContext(), { name: ‘myData01’ // 首选项文件的名称 } ) // 2、向首选项对象读取KV数据 // 2、向首选项对象读取KV数据 let v0 = p.getSync(“myFontSize”, 12) // 如果没有这个key,就返回默认值12,如果有这个key,就返回这个key的值 let v1 = p.getSync(“myBGColor”, ‘#fff’) let v2 = p.getSync(“autoStart”, false) let v3 = p.getSync(“proxy”, 999) // p.flushSync() 不需要刷新,因为读取数据的时候,并没有修改数据 console.log(’—首选项数据读取完毕—’) console.log(‘myFontSize:’, v0, v1, v2, v3) }) https://i-blog.csdnimg.cn/direct/18b5f629d2b14891b8cc08970030f459.png 完整代码: Button(‘2、向首选项对象读取KV数据’) .onClick(()=>{ // 1、先找到首选项对象 let p = preferences.getPreferencesSync(getContext(), { name: ‘myData01’ // 首选项文件的名称 } ) // 2、向首选项对象读取KV数据 let v0 = p.getSync(“myFontSize”, 12) // 如果没有这个key,就返回默认值12,如果有这个key,就返回这个key的值 let v1 = p.getSync(“myBGColor”, ‘#fff’) let v2 = p.getSync(“autoStart”, false) let v3 = p.getSync(“proxy”, 999) // p.flushSync() 不需要刷新,因为读取数据的时候,并没有修改数据 console.log(’—首选项数据读取完毕—’) console.log(‘myFontSize:’, v0, v1, v2, v3) })

3、修改首选项中的数据

 // 1、先找到首选项对象 let p = preferences.getPreferencesSync(getContext(), { name: ‘myData01’ // 首选项文件的名称 } ) 2、修改首选项中的数据 p.putSync(“myBGColor”, ‘#ff000000’) 3、完整代码 Button(‘3、修改首选项对象中的数据’) .onClick(()=>{ // 1、先找到首选项对象 let p = preferences.getPreferencesSync(getContext(), { name: ‘myData01’ // 首选项文件的名称 } ) // 2、向首选项对象修改数据 p.putSync(“myBGColor”, ‘#ff000000’) p.flushSync() // 刷新后,才能看到数据,把内存中的修改持久化到文件中 ctx.preferenceDir() console.log(‘首选项数据修改完成!’) })

必须p.flush(),如果不冲刷,只有当前内存中加载的首选项被修改了,外存中的文件没有被修改。

(如不加flush,控制台显示修改成功,但重新启动项目,会发现数据的值又会变成修改前的数据。如果使用flush,重新启动,数据的值依旧为修改后的值)

4、删除首选项对象中的数据

 // 1、先找到首选项对象 let p = preferences.getPreferencesSync(getContext(), { name: ‘myData01’ // 首选项文件的名称 } ) 2、修改首选项中的数据 // 向首选项对象删除数据 p.deleteSync(“myBGColor”); p.flushSync() 3、完整代码 Button(‘3、删除首选项对象中的数据’) .onClick(()=>{ // 1、先找到首选项对象 let p = preferences.getPreferencesSync(getContext(), { name: ‘myData01’ // 首选项文件的名称 } ) // 向首选项对象删除数据 p.deleteSync(“myBGColor”); p.flushSync() console.log(‘首选项数据删除完成!’); })

5、清空首选项中的数据(文件还在)

Button(‘5、清空首选项对象中的数据’) .onClick(()=>{ // 1、先找到首选项对象 let p = preferences.getPreferencesSync(getContext(), { name: ‘myData01’ // 首选项文件的名称 } ) // 向首选项对象删除数据 p.clearSync() p.flushSync() console.log(‘首选项数据清空完成!’) })

6、删除首选项文件(文件不在)

Button(‘5、删除首选项对象中的数据’) .onClick(async ()=>{ await preferences.deletePreferences(getContext(), ‘myData01’) console.log(‘首选项数据删除完成!’) })


[二、键值型数据库](

guides/data-persistence-by-kv-store#场景介绍 “二、键值型数据库”) 数据是有格式的话,用首选项(虽然是键值对,但不是无限多的)麻烦、如键-值。一般需要增删改查!

键值型数据库存储 键值对形式的数据,当需要存储的数据没有复杂的关系模型,比如每日的流水账记录、当前用户每日的上班出勤记录等,由于数据复杂度低,更容易兼容不同数据库版本和设备类型,因此推荐使用键值型数据库持久化此类数据。 约束限制: ● 设备协同数据库,针对每条记录,Key的长度≤896 Byte,Value的长度 <4 MB;

● 单版本数据库,针对每条记录, Key的长度≤1 KB,Value的长度<4 MB;

● 每个应用程序最多支持同时打开16个键值型分布式数据库;

● 键值型数据库事件回调方法中不允许进行阻塞操作,例如修改UI组件。

获取一个KVManager实例

若要使用键值型数据库,首先要获取一个KVManager实例,用于管理数据库对象。

// 1、创建KVStore管理器对象 let mgr = distributedKVStore.createKVManager({ bundleName: “com.swk.MyApplication11_09_morning”, context: getContext() })


创建并获取键值数据库。

// 2、使用管理器创建KVStore对象 let db: distributedKVStore.SingleKVStore = await mgr.getKVStore(‘myData02’, { securityLevel: distributedKVStore.SecurityLevel.S1 // 安全等级 S1最普通安全级别 S2 S3 S4 })

securityLevel: distributedKVStore.SecurityLevel.S1 // 安全等级 S1最普通安全级别 S2 S3 S4

安全级别说明
S1表示数据库的安全级别为低级别,数据的泄露、篡改、破坏、销毁可能会给个人或组织导致有限的不利影响。 例如,性别、国籍,用户申请记录等
S2表示数据库的安全级别为中级别,数据的泄露、篡改、破坏、销毁可能会给个人或组织导致严重的不利影响。 例如,个人详细通信地址,姓名昵称等
S3表示数据库的安全级别为高级别,数据的泄露、篡改、破坏、销毁可能会给个人或组织导致严峻的不利影响。 例如,个人实时精确定位信息、运动轨迹等
S4表示数据库的安全级别为关键级别,业界法律法规中定义的特殊数据类型,涉及个人的最私密领域的信息或者一旦泄露、篡改、破坏、销毁可能会给个人或组织造成重大的不利影响数据。 例如,政治观点、宗教、和哲学信仰、工会成员资格、基因数据、生物信息、健康和性生活状况、性取向等或设备认证鉴权、个人的信用卡等财务信息

调用[put()](

references/js-apis-distributedkvstore#put-1 “put()")方法向键值数据库中插入数据

db.put(‘20241001-IN’, 3000) db.put(‘20241005-OUT’, 1000) db.put(‘20241005-IN’, 5000) db.put(‘20241010-OUT’, 2000) db.put(‘20241015-OUT’, 2000) db.put(‘20241015-OUT’, 1000) console.log(’—键值对存储完毕—’)

说明

当Key值存在时,put()方法会修改其值,否则新增一条数据。 Button(‘1、保存键值对数据库’) .onClick(async () => { // 1、创建KVStore管理器对象 let mgr = distributedKVStore.createKVManager({ bundleName: “com.swk.MyApplication11_09_morning”, context: getContext() }) // 2、使用管理器创建KVStore对象 let db: distributedKVStore.SingleKVStore = await mgr.getKVStore(‘myData02’, { securityLevel: distributedKVStore.SecurityLevel.S1 // 安全等级 S1最普通安全级别 S2 S3 S4 }) db.put(‘20241001-IN’, 3000) db.put(‘20241005-OUT’, 1000) db.put(‘20241005-IN’, 5000) db.put(‘20241010-OUT’, 2000) db.put(‘20241015-OUT’, 2000) db.put(‘20241015-OUT’, 1000) console.log(’—键值对存储完毕—’) }) https://i-blog.csdnimg.cn/direct/f509a924da1b4a17bec88d46008b15f1.png

[putBatch()](

references/js-apis-distributedkvstore#putbatch-1 “putBatch()")批量添加键值对数据 // 3、批量添加键值对数据库 await db.putBatch([ // 批量添加键值对数据库 {key:‘20241001-IN’, value: { type:5, value:2334 }}, {key:‘20241001-OUT’, value: { type:5, value:3232 }}, {key:‘20241002-IN’, value: { type:5, value:2234 }}, {key:‘20241002-OUT’, value: { type:5, value:4543 }} ]) Button(‘7、批量添加键值对数据库—-putBatch()’) .onClick(async () => { // 1、创建KVStore管理器对象 let mgr = distributedKVStore.createKVManager({ bundleName: “com.swk.MyApplication11_09_morning”, context: getContext() }) // 2、使用管理器创建KVStore对象 let db: distributedKVStore.SingleKVStore = await mgr.getKVStore(‘myData02’, { securityLevel: distributedKVStore.SecurityLevel.S1 // 安全等级 S1最普通安全级别 S2 S3 S4 }) // 3、批量添加键值对数据库 await db.putBatch([ // 批量添加键值对数据库 {key:‘20241001-IN’, value: { type:5, value:2334 }}, {key:‘20241001-OUT’, value: { type:5, value:3232 }}, {key:‘20241002-IN’, value: { type:5, value:2234 }}, {key:‘20241002-OUT’, value: { type:5, value:4543 }} ]) console.log(’ —批量添加键值对数据库完毕—’) })

调用get()方法获取指定键的值

let v0 = await db.get(‘20241001-IN’) let v1 = await db.get(‘20241005-OUT’) let v2 = await db.get(‘20241005-IN’) let v3 = await db.get(‘20241010-OUT’) let v4 = await db.get(‘20241015-OUT’) Button(‘2、读取键值对数据库’) .onClick(async () => { // 1、创建KVStore管理器对象 let mgr = distributedKVStore.createKVManager({ bundleName: “com.swk.MyApplication11_09_morning”, context: getContext() }) // 2、使用管理器创建KVStore对象 let db: distributedKVStore.SingleKVStore = await mgr.getKVStore(‘myData02’, { securityLevel: distributedKVStore.SecurityLevel.S1 // 安全等级 S1最普通安全级别 S2 S3 S4 }) let v0 = await db.get(‘20241001-IN’) let v1 = await db.get(‘20241005-OUT’) let v2 = await db.get(‘20241005-IN’) let v3 = await db.get(‘20241010-OUT’) let v4 = await db.get(‘20241015-OUT’) console.log(’—键值对数据读取完毕—’, v0, v1, v2, v3, v4) }) 完整代码: import { distributedKVStore, preferences } from ‘@kit.ArkData’; @Entry @Component struct Index { build() { Column({ space: 16 }) { Text(‘ArkData-键值对存储’) .fontSize(30) Button(‘1、保存键值对数据库’) .onClick(async () => { // 1、创建KVStore管理器对象 let mgr = distributedKVStore.createKVManager({ bundleName: “com.swk.MyApplication11_09_morning”, context: getContext() }) // 2、使用管理器创建KVStore对象 let db: distributedKVStore.SingleKVStore = await mgr.getKVStore(‘myData02’, { securityLevel: distributedKVStore.SecurityLevel.S1 // 安全等级 S1最普通安全级别 S2 S3 S4 }) db.put(‘20241001-IN’, 1000) db.put(‘20241005-OUT’, 2000) db.put(‘20241005-IN’, 3000) db.put(‘20241010-OUT’, 4000) db.put(‘20241015-OUT’, 5000) db.put(‘20241015-OUT’, 6000) console.log(’—键值对存储完毕—’) }) Button(‘2、读取键值对数据库’) .onClick(async () => { // 1、创建KVStore管理器对象 let mgr = distributedKVStore.createKVManager({ bundleName: “com.swk.MyApplication11_09_morning”, context: getContext() }) // 2、使用管理器创建KVStore对象 let db: distributedKVStore.SingleKVStore = await mgr.getKVStore(‘myData02’, { securityLevel: distributedKVStore.SecurityLevel.S1 // 安全等级 S1最普通安全级别 S2 S3 S4 }) let v0 = await db.get(‘20241001-IN’) let v1 = await db.get(‘20241005-OUT’) let v2 = await db.get(‘20241005-IN’) let v3 = await db.get(‘20241010-OUT’) let v4 = await db.get(‘20241015-OUT’) console.log(’—键值对数据读取完毕—’, v0, v1, v2, v3, v4) }) } .height(‘100%’) .width(‘100%’) } } 效果: https://i-blog.csdnimg.cn/direct/70643b89efa04019b46b74b33e0c7819.pnghttps://i-blog.csdnimg.cn/direct/0941683e75a64d9d9458281268d3c48e.png

[getEntries](

references/js-apis-distributedkvstore#getentries “getEntries”) 获取匹配指定键前缀的所有键值对 // 2、使用管理器创建KVStore对象 let db: distributedKVStore.SingleKVStore = await mgr.getKVStore(‘myData02’, { securityLevel: distributedKVStore.SecurityLevel.S1 // 安全等级 S1最普通安全级别 S2 S3 S4 }) let list = await db.getEntries(‘2024’) // 模糊查询,返回一个数组,查询以2024开头的所有键值对 list.forEach((item)=>{ console.log(’<键:’+item.key, ‘值:’+JSON.stringify(item.value)+’>’) }) Button(‘3、读取键值对数据库(2)’) .onClick(async () => { // 1、创建KVStore管理器对象 let mgr = distributedKVStore.createKVManager({ bundleName: “com.swk.MyApplication11_09_morning”, context: getContext() }) // 2、使用管理器创建KVStore对象 let db: distributedKVStore.SingleKVStore = await mgr.getKVStore(‘myData02’, { securityLevel: distributedKVStore.SecurityLevel.S1 // 安全等级 S1最普通安全级别 S2 S3 S4 }) let list = await db.getEntries(‘2024’) // 模糊查询,返回一个数组,查询以2024开头的所有键值对 list.forEach((item)=>{ console.log(’<键:’+item.key, ‘值:’+JSON.stringify(item.value)+’>’) }) }) 完整代码: import { distributedKVStore, preferences } from ‘@kit.ArkData’; @Entry @Component struct Index { build() { Column({ space: 16 }) { Text(‘ArkData-键值对存储’) .fontSize(30) Button(‘1、保存键值对数据库’) .onClick(async () => { // 1、创建KVStore管理器对象 let mgr = distributedKVStore.createKVManager({ bundleName: “com.swk.MyApplication11_09_morning”, context: getContext() }) // 2、使用管理器创建KVStore对象 let db: distributedKVStore.SingleKVStore = await mgr.getKVStore(‘myData02’, { securityLevel: distributedKVStore.SecurityLevel.S1 // 安全等级 S1最普通安全级别 S2 S3 S4 }) db.put(‘20241001-IN’, 1000) db.put(‘20241005-OUT’, 2000) db.put(‘20241005-IN’, 3000) db.put(‘20241010-OUT’, 4000) db.put(‘20241015-OUT’, 5000) db.put(‘20241015-OUT’, 6000) console.log(’—键值对存储完毕—’) }) Button(‘2、读取键值对数据库’) .onClick(async () => { // 1、创建KVStore管理器对象 let mgr = distributedKVStore.createKVManager({ bundleName: “com.swk.MyApplication11_09_morning”, context: getContext() }) // 2、使用管理器创建KVStore对象 let db: distributedKVStore.SingleKVStore = await mgr.getKVStore(‘myData02’, { securityLevel: distributedKVStore.SecurityLevel.S1 // 安全等级 S1最普通安全级别 S2 S3 S4 }) let v0 = await db.get(‘20241001-IN’) let v1 = await db.get(‘20241005-OUT’) let v2 = await db.get(‘20241005-IN’) let v3 = await db.get(‘20241010-OUT’) let v4 = await db.get(‘20241015-OUT’) console.log(’—键值对数据读取完毕—’, v0, v1, v2, v3, v4) }) Button(‘3、读取键值对数据库(2)’) .onClick(async () => { // 1、创建KVStore管理器对象 let mgr = distributedKVStore.createKVManager({ bundleName: “com.swk.MyApplication11_09_morning”, context: getContext() }) // 2、使用管理器创建KVStore对象 let db: distributedKVStore.SingleKVStore = await mgr.getKVStore(‘myData02’, { securityLevel: distributedKVStore.SecurityLevel.S1 // 安全等级 S1最普通安全级别 S2 S3 S4 }) let list = await db.getEntries(‘2024’) // 模糊查询,返回一个数组,查询以2024开头的所有键值对 list.forEach((item)=>{ console.log(’<键:’+item.key, ‘值:’+JSON.stringify(item.value)+’>’) }) }) } .height(‘100%’) .width(‘100%’) } } 运行结果: https://i-blog.csdnimg.cn/direct/c2cdb434a2dc4f7290333feca83be44c.pnghttps://i-blog.csdnimg.cn/direct/947b18c2a5434505957b4fb938d7651d.png

修改指定键值中的数据

// 3、修改键值对数据库 await db.put(‘20241001-IN’, 900) // 修改,既是添加,又是修改

调用delete()方法删除指定键值的数据

// 3、删除键值对数据库 await db.delete(‘20241001-IN’)

6、删除整个键值对数据库

await mgr.deleteKVStore(’“com.swk.MyApplication11_09_morning”’,‘myData02’) Button(‘6、删除整个键值对数据库’) .onClick(async () => { // 1、创建KVStore管理器对象 let mgr = distributedKVStore.createKVManager({ bundleName: “com.swk.MyApplication11_09_morning”, context: getContext() }) await mgr.deleteKVStore(’“com.swk.MyApplication11_09_morning”’,‘myData02’) }) 通过storeId的值删除指定的分布式键值数据库

三、通过关系型数据库 实现数据持久化

1.向关系型数据库中写出数据

1.打开关系型数据库(没有的话,会自动创建数据库myData03)

let db = await relationalStore.getRdbStore(getContext(), { name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 // 安全级别 })

let sql = ‘CREATE TABLE friends(fid INTEGER PRIMARY KEY AUTOINCREMENT, fname VARCHAR(32), salary FLOAT, isMarried INT )’ // SQLite没有BOOLEAN类型,0表示0表示false,1表示true // SQLite:INT类型无法自增,需要使用INTEGER 类型 // MYSQL自增:AUTO_INCREMENT, SQLite自增:AUTOINCREMENT

https://i-blog.csdnimg.cn/direct/a27b49c898cd44388e84fb24bb973a21.png


2、如果不存在“我的联系人”表的话,就创建它

if (db.version === 0) { // 数据的版本号为0,说明数据库还没有创建表,需要创建表 let sql = ‘CREATE TABLE friends(fid INTEGER PRIMARY KEY AUTOINCREMENT, fname VARCHAR(32), salary FLOAT, isMarried INT )’ // SQLite没有BOOLEAN类型,0表示0表示false,1表示true db.executeSql(sql) } else if (db.version === 1) { // 数据的版本号为1,说明数据库已经创建了表,不需要创建表,此处可以再创建表 }


3、向“我的联系人表中”插入数据

// 3、向“我的联系人表中”插入数据 let rid1 = db.insertSync(“friends”, {fid:1, fname:‘汤姆’, salary: 18000, isMarried:0}) console.log(’—一行数据插入成功!行号为:’, rid1) let rid2 = db.insertSync(“friends”, {fid:5, fname:‘杰瑞’, salary: 20000, isMarried:1}) console.log(’—一行数据插入成功!行号为:’, rid2) let rid3 = db.insertSync(“friends”, {fid:8, fname:‘玛丽’, salary: 8000, isMarried:1}) console.log(’—一行数据插入成功!行号为:’, rid3) let rid4 = db.insertSync(“friends”, {fid:12, fname:‘琼斯’, salary: 12000, isMarried:0}) console.log(’—一行数据插入成功!行号为:’, rid4) // 4、关闭关系型数据库 console.log(’—关系型数据库刷新完毕—’) await db.close() 完整代码: import { distributedKVStore, preferences, relationalStore } from ‘@kit.ArkData’; import List from ‘@ohos.util.List’; @Entry @Component struct Index { build() { Column({ space: 16 }) { Text(‘ArkData Kit - 关系型数据库存储’) .fontSize(30) Button(‘1.向关系型数据库中写出数据’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、如果不存在“我的联系人”表的话,就创建它 if (db.version === 0) { // 数据的版本号为0,说明数据库还没有创建表,需要创建表 let sql = ‘CREATE TABLE friends(fid INTEGER PRIMARY KEY AUTOINCREMENT, fname TEXT, salary REAL, isMarried NUMERIC )’ // SQLite没有BOOLEAN类型,0表示0表示false,1表示true // SQLite中 :INT类型无法自增,需要使用INTEGER类型 // MYSQL自增:AUTO_INCREMENT, SQLite自增:AUTOINCREMENT // MySQL中的TEXT类型:指大型文本列,在SQLite中是TEXT类型指任何文本类型 // MYSQL中有BOOLEAN类型,SQLite中没有BOOLEAN类型,推荐使用NUMERIC,0表示false,1表示true db.executeSql(sql) } else if (db.version === 1) { // 数据的版本号为1,说明数据库已经创建了表,不需要创建表,此处可以再创建表 } // 3、向“我的联系人表中”插入数据 let rid1 = db.insertSync(“friends”, {fid:1, fname:‘汤姆’, salary: 18000, isMarried:0}) console.log(’—一行数据插入成功!行号为:’, rid1) let rid2 = db.insertSync(“friends”, {fid:null, fname:‘杰瑞’, salary: 20000, isMarried:1}) console.log(’—一行数据插入成功!行号为:’, rid2) let rid3 = db.insertSync(“friends”, {fid:8, fname:‘玛丽’, salary: 8000, isMarried:1}) console.log(’—一行数据插入成功!行号为:’, rid3) let rid4 = db.insertSync(“friends”, {fid:null, fname:‘琼斯’, salary: 12000, isMarried:0}) console.log(’—一行数据插入成功!行号为:’, rid4) // 4、关闭关系型数据库 console.log(’—关系型数据库刷新完毕—’) await db.close() }) } .height(‘100%’) .width(‘100%’) } } 效果: https://i-blog.csdnimg.cn/direct/5bcee62c2bcc49c3b1bb740a835f5c98.pnghttps://i-blog.csdnimg.cn/direct/ce4261a1402842c1be555f222fd3c767.png


2、删除

https://i-blog.csdnimg.cn/direct/48b1d155a9914ac281d86c9dbf69c5a6.png Button(‘2.删除关系型数据库中的数据行’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、删除指定编号的好友信息 let p = new relationalStore.RdbPredicates(“friends”) let num = db.deleteSync(p.equalTo(“fid”, 1)) console.log(---删除了${num}行数据---) await db.close() })

3、修改关系型数据库的数据

// 2、修改制定编号的好友信息 let p = new relationalStore.RdbPredicates(“friends”) // 谓词,相当于SQL中的where条件,查询的表名 let num = db.updateSync({fname:“乔伊斯”, salary: 10002}, p.equalTo(“fid”, 9)) // 修改指定编号的好友信息 console.log(’—修改了’+num+‘行数据—’) Button(‘3.修改关系型数据库中的数据行’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 // 安全级别 S1最普通安全级别 S2 S3 S4 }) // 2、修改制定编号的好友信息 let p = new relationalStore.RdbPredicates(“friends”) // 谓词,相当于SQL中的where条件,查询的表名 let num = db.updateSync({fname:“乔伊斯”, salary: 10002}, p.equalTo(“fid”, 9)) // 修改指定编号的好友信息 console.log(’—修改了’+num+‘行数据—’) await db.close() }) https://i-blog.csdnimg.cn/direct/6cb08d606493423b8d76ce084dc926fa.png https://i-blog.csdnimg.cn/direct/f998469dd9014dbcb9c92c5899a7bbf6.png https://i-blog.csdnimg.cn/direct/a91c89f2967741d5981fefee8ca3d616.png

4-1 查询关系型数据库的所有行数据

Button(‘4-1.查询关系型数据库中的所有行数据’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { // 打开关系型数据库 name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、向关系型数据库中发出查询语句 // let sql = ‘SELECT fid,fname,salary FROM friends’ // 写法一:指定列 let sql = ‘SELECT * FROM friends’ let rs = db.querySqlSync(sql) // 查询语句的结果集,是一个二维数组,每一行是一个数组,每一列是一个数组的元素,每一行的列数是一样的 console.log(‘查询到数据了,总共的数据行数:’, rs.rowCount) await db.close() })

let rs = db.querySqlSync(sql)

查询语句的结果集,是一个二维数组, 每一行是一个数组,每一列是一个数组的元素,每一行的列数是一样的 https://i-blog.csdnimg.cn/direct/bdc035feb20f4c1392b7761c19b566a8.png // 3、遍历结果集,把每一行的数据都打印出来,使用rs对象的getXXX()方法获取每一行的数据 while (rs.goToNextRow()) { // 获取下一行数据,如果有数据,返回true,如果没有数据,返回false console.log(’—’, rs.getLong(0), rs.getString(1), rs.getDouble(2), rs.getDouble(3)) // 0表示第一列fid,1表示第二列fname,2表示第三列salary, 3表示第四列isMarried } 查询代码 https://i-blog.csdnimg.cn/direct/f398b0a24f0541539be2c229d719400f.png Button(‘4-1.查询关系型数据库中的所有行数据’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { // 打开关系型数据库 name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、向关系型数据库中发出查询语句 // let sql = ‘SELECT fid,fname,salary FROM friends’ // 写法一:指定列 let sql = ‘SELECT * FROM friends’ let rs = db.querySqlSync(sql) // 查询语句的结果集,是一个二维数组,每一行是一个数组,每一列是一个数组的元素,每一行的列数是一样的 console.log(‘查询到数据了,总共的数据行数:’, rs.rowCount) // 3、遍历结果集,把每一行的数据都打印出来,使用rs对象的getXXX()方法获取每一行的数据 while (rs.goToNextRow()) { // 获取下一行数据,如果有数据,返回true,如果没有数据,返回false console.log(’—’, rs.getLong(0), rs.getString(1), rs.getDouble(2), rs.getDouble(3)) // 0表示第一列fid,1表示第二列fname,2表示第三列salary, 3表示第四列isMarried } await db.close() }) 注意:这里是确定数据库 myData03 肯定存在,所有没有判断它是否为0的语句。 完整代码: import { distributedKVStore, preferences, relationalStore } from ‘@kit.ArkData’; import List from ‘@ohos.util.List’; @Entry @Component struct Index { build() { Column({ space: 16 }) { Text(‘ArkData Kit - 关系型数据库存储’) .fontSize(30) Button(‘1.向关系型数据库中写出数据’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、如果不存在“我的联系人”表的话,就创建它 if (db.version === 0) { // 数据的版本号为0,说明数据库还没有创建表,需要创建表 let sql = ‘CREATE TABLE friends(fid INTEGER PRIMARY KEY AUTOINCREMENT, fname TEXT, salary REAL, isMarried NUMERIC )’ // SQLite没有BOOLEAN类型,0表示0表示false,1表示true // SQLite中 :INT类型无法自增,需要使用INTEGER类型 // MYSQL自增:AUTO_INCREMENT, SQLite自增:AUTOINCREMENT // MySQL中的TEXT类型:指大型文本列,在SQLite中是TEXT类型指任何文本类型 // MYSQL中有BOOLEAN类型,SQLite中没有BOOLEAN类型,推荐使用NUMERIC,0表示false,1表示true await db.executeSql(sql) } else if (db.version === 1) { // 数据的版本号为1,说明数据库已经创建了表,不需要创建表,此处可以再创建表 } // 3、向“我的联系人表中”插入数据 let rid1 = db.insertSync(“friends”, {fid:1, fname:‘汤姆’, salary: 18000, isMarried:0}) console.log(’—一行数据插入成功!行号为:’, rid1) let rid2 = db.insertSync(“friends”, {fid:null, fname:‘杰瑞’, salary: 20000, isMarried:1}) console.log(’—一行数据插入成功!行号为:’, rid2) let rid3 = db.insertSync(“friends”, {fid:8, fname:‘玛丽’, salary: 8000, isMarried:1}) console.log(’—一行数据插入成功!行号为:’, rid3) let rid4 = db.insertSync(“friends”, {fid:null, fname:‘琼斯’, salary: 12000, isMarried:0}) console.log(’—一行数据插入成功!行号为:’, rid4) // 4、关闭关系型数据库 console.log(’—关系型数据库刷新完毕—’) await db.close() }) Button(‘4-1.查询关系型数据库中的所有行数据’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { // 打开关系型数据库 name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、向关系型数据库中发出查询语句 // let sql = ‘SELECT fid,fname,salary FROM friends’ // 写法一:指定列 let sql = ‘SELECT * FROM friends’ let rs = db.querySqlSync(sql) // 查询语句的结果集,是一个二维数组,每一行是一个数组,每一列是一个数组的元素,每一行的列数是一样的 console.log(‘查询到数据了,总共的数据行数:’, rs.rowCount) // 3、遍历结果集,把每一行的数据都打印出来,使用rs对象的getXXX()方法获取每一行的数据 while (rs.goToNextRow()) { // 获取下一行数据,如果有数据,返回true,如果没有数据,返回false console.log(’—’, rs.getLong(0), rs.getString(1), rs.getDouble(2), rs.getDouble(3)) // 0表示第一列fid,1表示第二列fname,2表示第三列salary, 3表示第四列isMarried } await db.close() }) } .height(‘100%’) .width(‘100%’) } } 效果: https://i-blog.csdnimg.cn/direct/a966aa57d0b74b4fb57c9e55c3c4b76b.pnghttps://i-blog.csdnimg.cn/direct/333a88266fbb46db8ae662872568dede.png


4-1-2

https://i-blog.csdnimg.cn/direct/748065a82a9645e6874697f38974c833.png Button(‘4-1-2.查询关系型数据库中的所有行数据’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { // 打开关系型数据库 name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、向关系型数据库中发出查询谓词 let p = new relationalStore.RdbPredicates(“friends”) // From friends // let rs = db.querySync(p) let rs = db.querySync(p, [‘fid’, ‘fname’, ‘salary’, ‘isMarried’]) // 可以指定列, 如果不指定列,默认查询所有列, 列名的顺序必须和查询语句中的列名的顺序一致 console.log(‘查询到数据了,总共的数据行数:’, rs.rowCount) // 3、遍历结果集,把每一行的数据都打印出来,使用rs对象的getXXX()方法获取每一行的数据 while (rs.goToNextRow()) { // 获取下一行数据,如果有数据,返回true,如果没有数据,返回false console.log(’—’, rs.getLong(0), rs.getString(1), rs.getDouble(2), rs.getDouble(3)) // 0表示第一列fid,1表示第二列fname,2表示第三列salary, 3表示第四列isMarried } await db.close() })

https://i-blog.csdnimg.cn/direct/50c8b8df24144875a334869d5408fcc8.png

4-2 查询关系型数据库中的某一行数据

// 2、向关系型数据库中发出查询语句 let sql = ‘SELECT fid,fname,salary,isMarried FROM friends where fid = 9’ // 写法一:指定列 let rs = db.querySqlSync(sql) console.log(‘查询到数据了,总共的数据行数:’, rs.rowCount) if (rs.goToNextRow()) { // 获取下一行数据,如果有数据,返回true,如果没有数据,返回false console.log(’—’, rs.getLong(0), rs.getString(1), rs.getDouble(2), rs.getDouble(3)) // 0表示第一列fid,1表示第二列fname,2表示第三列salary, 3表示第四列isMarried } else { console.log(‘根据您提供的好友编号,没有找到好友!’) } await db.close() })

let sql = ‘SELECT fid,fname,salary,isMarried FROM friends where fid = 9’

where 条件判定 注意:要防止SQL注入:(用户的输入绝不可以用 加法 拼接)

描述:用户的输入如果直接拼接到字符串中,可能会影响判定。

如:一系统用户名:root, 密码:123456 ,判定条件为

select * from table where uname =账户 and upwd = 密码

如果用户在登入时,账户输入正确为root,但密码忘记,却用” ’ or ’ 1’ = ‘1’ ’ “,可能登入成功。

因为此时判断语句为

select * from table where uname =“root ” and upwd = ’ ’ or ’ 1’ = ‘1’ ’ '

https://i-blog.csdnimg.cn/direct/de62c9d4bac64ab6a8413f20f92c2d25.png https://i-blog.csdnimg.cn/direct/38d39f24f79d416e90a8446b399266c4.png import { distributedKVStore, preferences, relationalStore } from ‘@kit.ArkData’; import List from ‘@ohos.util.List’; @Entry @Component struct Index { build() { Column({ space: 16 }) { Text(‘ArkData Kit - 关系型数据库存储’) .fontSize(30) Button(‘1.向关系型数据库中写出数据’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、如果不存在“我的联系人”表的话,就创建它 if (db.version === 0) { // 数据的版本号为0,说明数据库还没有创建表,需要创建表 let sql = ‘CREATE TABLE friends(fid INTEGER PRIMARY KEY AUTOINCREMENT, fname TEXT, salary REAL, isMarried NUMERIC )’ // SQLite没有BOOLEAN类型,0表示0表示false,1表示true // SQLite中 :INT类型无法自增,需要使用INTEGER类型 // MYSQL自增:AUTO_INCREMENT, SQLite自增:AUTOINCREMENT // MySQL中的TEXT类型:指大型文本列,在SQLite中是TEXT类型指任何文本类型 // MYSQL中有BOOLEAN类型,SQLite中没有BOOLEAN类型,推荐使用NUMERIC,0表示false,1表示true await db.executeSql(sql) } else if (db.version === 1) { // 数据的版本号为1,说明数据库已经创建了表,不需要创建表,此处可以再创建表 } // 3、向“我的联系人表中”插入数据 let rid1 = db.insertSync(“friends”, {fid:1, fname:‘汤姆’, salary: 18000, isMarried:0}) console.log(’—一行数据插入成功!行号为:’, rid1) let rid2 = db.insertSync(“friends”, {fid:null, fname:‘杰瑞’, salary: 20000, isMarried:1}) console.log(’—一行数据插入成功!行号为:’, rid2) let rid3 = db.insertSync(“friends”, {fid:8, fname:‘玛丽’, salary: 8000, isMarried:1}) console.log(’—一行数据插入成功!行号为:’, rid3) let rid4 = db.insertSync(“friends”, {fid:null, fname:‘琼斯’, salary: 12000, isMarried:0}) console.log(’—一行数据插入成功!行号为:’, rid4) // 4、关闭关系型数据库 console.log(’—关系型数据库刷新完毕—’) await db.close() }) Button(‘2.删除关系型数据库中的数据行’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、如果不存在“我的联系人”表的话,就创建它 if (db.version === 0) { // 数据的版本号为0,说明数据库还没有创建表,需要创建表 let sql = ‘CREATE TABLE friends(fid INTEGER PRIMARY KEY AUTOINCREMENT, fname TEXT, salary REAL, isMarried NUMERIC )’ // SQLite没有BOOLEAN类型,0表示0表示false,1表示true await db.executeSql(sql) } else if (db.version === 1) { // 数据的版本号为1,说明数据库已经创建了表,不需要创建表,此处可以再创建表 } await db.close() }) Button(‘3.删除关系型数据库中的数据行’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、如果不存在“我的联系人”表的话,就创建它 if (db.version === 0) { // 数据的版本号为0,说明数据库还没有创建表,需要创建表 let sql = ‘CREATE TABLE friends(fid INTEGER PRIMARY KEY AUTOINCREMENT, fname TEXT, salary REAL, isMarried NUMERIC )’ // SQLite没有BOOLEAN类型,0表示0表示false,1表示true await db.executeSql(sql) } else if (db.version === 1) { // 数据的版本号为1,说明数据库已经创建了表,不需要创建表,此处可以再创建表 } await db.close() }) Button(‘4-1.查询关系型数据库中的所有行数据’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { // 打开关系型数据库 name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、向关系型数据库中发出查询语句 let sql = ‘SELECT fid,fname,salary,isMarried FROM friends’ // 写法一:指定列 // let sql = ‘SELECT * FROM friends’ let rs = db.querySqlSync(sql) // 查询语句的结果集,是一个二维数组,每一行是一个数组,每一列是一个数组的元素,每一行的列数是一样的 console.log(‘查询到数据了,总共的数据行数:’, rs.rowCount) // 3、遍历结果集,把每一行的数据都打印出来,使用rs对象的getXXX()方法获取每一行的数据 while (rs.goToNextRow()) { // 获取下一行数据,如果有数据,返回true,如果没有数据,返回false console.log(’—’, rs.getLong(0), rs.getString(1), rs.getDouble(2), rs.getDouble(3)) // 0表示第一列fid,1表示第二列fname,2表示第三列salary, 3表示第四列isMarried } await db.close() }) Button(‘4-2.查询关系型数据库中的某行数据’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、向关系型数据库中发出查询语句 let id = 9; // let sql = ‘SELECT fid,fname,salary,isMarried FROM friends where fid + i’ // SQL注入,拼接 let sql = ‘SELECT fid,fname,salary,isMarried FROM friends where fid = ?’ // 正确写法 let rs = db.querySqlSync(sql, [id]) console.log(‘查询到数据了,总共的数据行数:’, rs.rowCount) if (rs.goToNextRow()) { // 获取下一行数据,如果有数据,返回true,如果没有数据,返回false console.log(’—’, rs.getLong(0), rs.getString(1), rs.getDouble(2), rs.getDouble(3)) // 0表示第一列fid,1表示第二列fname,2表示第三列salary, 3表示第四列isMarried } else { console.log(‘根据您提供的好友编号,没有找到好友!’) } await db.close() }) } .height(‘100%’) .width(‘100%’) } } https://i-blog.csdnimg.cn/direct/e4300065172c4b22ab31cc46ec58c608.pnghttps://i-blog.csdnimg.cn/direct/ecd1020b932640089cc50841871cafdc.png


4-2-2 谓词查询

https://i-blog.csdnimg.cn/direct/acbe26ee2448442485e95cad16eccee9.png


https://i-blog.csdnimg.cn/direct/d7378f08ef284945b8d838d7618730c8.png Button(‘4-2-2.查询关系型数据库中的某行数据’) .onClick(async () => { // 1、打开关系型数据库(没有的话,会自动创建数据库myData03) let db = await relationalStore.getRdbStore(getContext(), { name: ‘myData03’, securityLevel: relationalStore.SecurityLevel.S1 }) // 2、向关系型数据库中发出查询语句 let p = new relationalStore.RdbPredicates(“friends”) // 正确写法 p.equalTo(“fid”, 9) // WHERE fid = ?,天然防止SQL注入 let rs = db.querySync(p) console.log(‘查询到数据了,总共的数据行数:’, rs.rowCount) if (rs.goToNextRow()) { // 获取下一行数据,如果有数据,返回true,如果没有数据,返回false console.log(’—’, rs.getLong(0), rs.getString(1), rs.getDouble(2), rs.getDouble(3)) // 0表示第一列fid,1表示第二列fname,2表示第三列salary, 3表示第四列isMarried } else { console.log(‘根据您提供的好友编号,没有找到好友!’) } await db.close() })