【鸿蒙HarmonyOS开发笔记】通用型工具封装之关系型数据库操作类的封装

概述

开发中难免遇到操作关系型数据库的场景,但是原生的relationalStore使用起来略显繁琐,此文封装一个通用的关系型数据库增删改查的工具类,只需要少量修改配置即可使用,大幅简化我们的开发成本,提高开发效率

完整代码在文章结尾,拿代码直接划到结尾即可


1.封装初始化数据库函数与建表函数

createTable函数只需要传入建表SQL语句即可,需要自行准备哦

//  操作的数据库名称,
const DB_FILENAME: string = 'OliannaWen.db'class DbUtil {// 使用变量来获取关系型数据库操作对象rdbStore: relationalStore.RdbStore// 初始化数据库initDB(context: common.UIAbilityContext): Promise<void> {let config: relationalStore.StoreConfig = {// 数据库名称name: DB_FILENAME,// 数据库操作安全等级securityLevel: relationalStore.SecurityLevel.S1}return new Promise<void>((resolve, reject) => {// 获取关系型数据库操作对象relationalStore.getRdbStore(context, config).then(rdbStore => {this.rdbStore = rdbStore// 记录日志Logger.debug('rdbStore 初始化完成!')resolve()}).catch(reason => {Logger.debug('rdbStore 初始化异常', JSON.stringify(reason))reject(reason)})})}// 创建表函数,传入创建表语句createTable(createSQL: string): Promise<void> {return new Promise((resolve, reject) => {this.rdbStore.executeSql(createSQL).then(() => {Logger.debug('创建表成功', createSQL)resolve()}).catch(err => {Logger.error('创建表失败,' + err.message, JSON.stringify(err))reject(err)})})}

一般来讲,我们都会在EntryAbility.ets中去初始化数据库,调用DbUtil.initDB传入context即可

import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
import DbUtil from '../common/utils/DbUtil';
import RecordModel from '../model/RecordModel'
import PreferenceUtyil from "../common/utils/PreferenceUtil"export default class EntryAbility extends UIAbility {async  onCreate(want, launchParam) {// 加载用户首选项PreferenceUtyil.loadPreference(this.context)// 初始化RDB工具await DbUtil.initDB(this.context)// 创建表DbUtil.createTable(RecordModel.getCreateTableSql())hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');}

新增方法

一般来说,我们实际开发使用的实体字段和数据库并不一定是一致的,所以需要先构建映射关系来保证正确插入

export interface ColumnInfo{// 实体字段name: string// 映射到数据库对应的字段columnName: string// 数据库字段类型type: ColumnType
}export enum ColumnType{LONG,DOUBLE,STRING,BLOB
}

使用前需要自行准备映射关系,例如

const COLUMNS: ColumnInfo[] = [{name: 'id', columnName: 'id', type: ColumnType.LONG},{name: 'typeId', columnName: 'type_id', type: ColumnType.LONG},{name: 'itemId', columnName: 'item_id', type: ColumnType.LONG},{name: 'amount', columnName: 'amount', type: ColumnType.DOUBLE},{name: 'createTime', columnName: 'create_time', type: ColumnType.LONG}
]

然后我们实现新增的通用方法

  // 建立insert方法的映射关系(实体数据插入到数据库的字段映射)buildValueBucket(obj: any, columns: ColumnInfo[]): relationalStore.ValuesBucket {let value = {}columns.forEach(info => {let val = obj[info.name]if (typeof val !== 'undefined') {value[info.columnName] = val}})return value}// 新增方法,参数为表名称和新增对象insert(tableName: string, obj: any, columns: ColumnInfo[]): Promise<number> {return new Promise((resolve, reject) => {// 1.构建新增数据let value = this.buildValueBucket(obj, columns)// 2.新增this.rdbStore.insert(tableName, value, (err, id) => {if (err) {Logger.error('新增失败!', JSON.stringify(err))reject(err)} else {Logger.debug('新增成功!新增id:', id.toString())resolve(id)}})})}

删除方法比较简单,不做展开

  // 删除方法,传入删除条件delete(predicates: relationalStore.RdbPredicates): Promise<number> {return new Promise((resolve, reject) => {this.rdbStore.delete(predicates, (err, rows) => {if (err) {Logger.error('删除失败!', JSON.stringify(err))reject(err)} else {Logger.debug('删除成功!删除行数:', rows.toString())resolve(rows)}})})}

查询方法

查询方法略微麻烦,我们先按照条件查询出目标,因为relationalStore返回的是结果集,所以我们需要自己再解析一边,代码如下

  // 查询方法,传入查询条件,字段,返回解析后的结果queryForList<T>(predicates: relationalStore.RdbPredicates, columns: ColumnInfo[]): Promise<T[]> {return new Promise((resolve, reject) => {this.rdbStore.query(predicates, columns.map(info => info.columnName), (err, result) => {if (err) {Logger.error('查询失败!', JSON.stringify(err))reject(err)} else {Logger.debug('查询成功!查询行数:', result.rowCount.toString())resolve(this.parseResultSet(result, columns))}})})}// 解析结果集parseResultSet<T> (result: relationalStore.ResultSet, columns: ColumnInfo[]): T[] {// 1.声明最终返回的结果let arr = []// 2.判断是否有结果if (result.rowCount <= 0) {return arr}// 3.处理结果while (!result.isAtLastRow) {// 3.1.去下一行result.goToNextRow()// 3.2.解析这行数据,转为对象let obj = {}columns.forEach(info => {let val = nullswitch (info.type) {case ColumnType.LONG:val = result.getLong(result.getColumnIndex(info.columnName))breakcase ColumnType.DOUBLE:val = result.getDouble(result.getColumnIndex(info.columnName))breakcase ColumnType.STRING:val = result.getString(result.getColumnIndex(info.columnName))breakcase ColumnType.BLOB:val = result.getBlob(result.getColumnIndex(info.columnName))break}obj[info.name] = val})// 3.3.将对象填入结果数组arr.push(obj)Logger.debug('查询到数据:', JSON.stringify(obj))}return arr}

完整代码

使用时修改 DB_FILENAME ,并且提供实体数据字段与数据库字段的映射关系数组

DbUtil.ts

import common from '@ohos.app.ability.common';
import relationalStore from '@ohos.data.relationalStore';
import { ColumnInfo, ColumnType } from '../bean/ColumnInfo';
import Logger from './Logger';//  操作的数据库名称
const DB_FILENAME: string = 'OliannaWen.db'class DbUtil {// 使用变量来获取关系型数据库操作对象rdbStore: relationalStore.RdbStore// 初始化数据库initDB(context: common.UIAbilityContext): Promise<void> {let config: relationalStore.StoreConfig = {// 数据库名称name: DB_FILENAME,// 数据库操作安全等级securityLevel: relationalStore.SecurityLevel.S1}return new Promise<void>((resolve, reject) => {// 获取关系型数据库操作对象relationalStore.getRdbStore(context, config).then(rdbStore => {this.rdbStore = rdbStore// 记录日志Logger.debug('rdbStore 初始化完成!')resolve()}).catch(reason => {Logger.debug('rdbStore 初始化异常', JSON.stringify(reason))reject(reason)})})}// 创建表函数,传入创建表语句createTable(createSQL: string): Promise<void> {return new Promise((resolve, reject) => {this.rdbStore.executeSql(createSQL).then(() => {Logger.debug('创建表成功', createSQL)resolve()}).catch(err => {Logger.error('创建表失败,' + err.message, JSON.stringify(err))reject(err)})})}// 建立insert方法的映射关系(实体数据插入到数据库的字段映射)buildValueBucket(obj: any, columns: ColumnInfo[]): relationalStore.ValuesBucket {let value = {}columns.forEach(info => {let val = obj[info.name]if (typeof val !== 'undefined') {value[info.columnName] = val}})return value}// 新增方法,参数为表名称和新增对象insert(tableName: string, obj: any, columns: ColumnInfo[]): Promise<number> {return new Promise((resolve, reject) => {// 1.构建新增数据let value = this.buildValueBucket(obj, columns)// 2.新增this.rdbStore.insert(tableName, value, (err, id) => {if (err) {Logger.error('新增失败!', JSON.stringify(err))reject(err)} else {Logger.debug('新增成功!新增id:', id.toString())resolve(id)}})})}// 删除方法,传入删除条件delete(predicates: relationalStore.RdbPredicates): Promise<number> {return new Promise((resolve, reject) => {this.rdbStore.delete(predicates, (err, rows) => {if (err) {Logger.error('删除失败!', JSON.stringify(err))reject(err)} else {Logger.debug('删除成功!删除行数:', rows.toString())resolve(rows)}})})}// 查询方法,传入查询条件,字段,返回结果queryForList<T>(predicates: relationalStore.RdbPredicates, columns: ColumnInfo[]): Promise<T[]> {return new Promise((resolve, reject) => {this.rdbStore.query(predicates, columns.map(info => info.columnName), (err, result) => {if (err) {Logger.error('查询失败!', JSON.stringify(err))reject(err)} else {Logger.debug('查询成功!查询行数:', result.rowCount.toString())resolve(this.parseResultSet(result, columns))}})})}// 解析结果集parseResultSet<T> (result: relationalStore.ResultSet, columns: ColumnInfo[]): T[] {// 1.声明最终返回的结果let arr = []// 2.判断是否有结果if (result.rowCount <= 0) {return arr}// 3.处理结果while (!result.isAtLastRow) {// 3.1.去下一行result.goToNextRow()// 3.2.解析这行数据,转为对象let obj = {}columns.forEach(info => {let val = nullswitch (info.type) {case ColumnType.LONG:val = result.getLong(result.getColumnIndex(info.columnName))breakcase ColumnType.DOUBLE:val = result.getDouble(result.getColumnIndex(info.columnName))breakcase ColumnType.STRING:val = result.getString(result.getColumnIndex(info.columnName))breakcase ColumnType.BLOB:val = result.getBlob(result.getColumnIndex(info.columnName))break}obj[info.name] = val})// 3.3.将对象填入结果数组arr.push(obj)Logger.debug('查询到数据:', JSON.stringify(obj))}return arr}}let dbUtil: DbUtil = new DbUtil();export default dbUtil as DbUtil

ColumnInfo.ts

export interface ColumnInfo{// 实体字段name: string// 映射到数据库对应的字段columnName: string// 数据库字段类型type: ColumnType
}export enum ColumnType{LONG,DOUBLE,STRING,BLOB
}

Logger.ts

import hilog from '@ohos.hilog';const LOGGER_PREFIX: string = 'OliannaWen.db';class Logger {private domain: number;private prefix: string;// format Indicates the log format string.private format: string = '%{public}s, %{public}s';/*** constructor.** @param prefix Identifies the log tag.* @param domain Indicates the service domain, which is a hexadecimal integer ranging from 0x0 to 0xFFFFF* @param args Indicates the log parameters.*/constructor(prefix: string = '', domain: number = 0xFF00) {this.prefix = prefix;this.domain = domain;}debug(...args: string[]): void {hilog.debug(this.domain, this.prefix, this.format, args);}info(...args: string[]): void {hilog.info(this.domain, this.prefix, this.format, args);}warn(...args: string[]): void {hilog.warn(this.domain, this.prefix, this.format, args);}error(...args: string[]): void {hilog.error(this.domain, this.prefix, this.format, args);}
}export default new Logger(LOGGER_PREFIX, 0xFF02);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/782386.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法学习——LeetCode力扣单调栈篇

算法学习——LeetCode力扣单调栈篇 739. 每日温度 739. 每日温度 - 力扣&#xff08;LeetCode&#xff09; 描述 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个…

vue图片压缩

1.使用插件 1.image-conversion 1.1安装 npm i image-conversion --save 1.2使用 //引用 import * as imageConversion from image-conversion//使用(主要方法)//压缩到指定大小 beforeAvatarUpload(file) {const isJpgOrPng file.type image/jpeg || file.type image/png…

关系型数据库mysql(7)sql高级语句①

目录 一.MySQL常用查询 1.按关键字&#xff08;字段&#xff09;进行升降排序 按分数排序 &#xff08;默认为升序&#xff09; 按分数升序显示 按分数降序显示 根据条件进行排序&#xff08;加上where&#xff09; 根据多个字段进行排序 ​编辑 2.用或&#xff08;or&…

Rust语言中Option和Result两种类型的使用

异同之处 不同之处主要在于用途不同 都可以用于Error handle的&#xff0c;都是枚举类型,都可以作为function的返回类型&#xff0c; 二者源码如下 pub enum Option<T> {None,Some(T), }pub enum Result<T, E> {Ok(T),Err(E), }为什么这么设计 有场景才有设计的…

ESP8266 控制 LED 亮灭

一、引脚对应 二、按键控制 LED 亮灭 2.1样例1 #include <ESP8266WiFi.h>const int ledPin D2; // LED 连接到 D2 引脚 const int keyPin D4; // 按键连接到 D4 引脚volatile bool flag false; // 记录 LED 状态的标志// 外部中断处理函数 ICACHE_RAM_ATTR void han…

重新温习广软puthon爬虫技术。

下面是我不断试错的一个过程&#xff0c;好多知识点全忘记了&#xff0c;只能不断调实例&#xff0c;不断优化&#xff0c;重构&#xff0c;实现自己的需求。下面是我的运行截图。还是导包的问题。 个人感觉关键的还是这几部&#xff0c;被划了下划线的&#xff0c;存在问题&a…

【智能算法】猎人猎物算法(HPO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2022年&#xff0c;Naruei等人受到自然界动物猎食过程启发&#xff0c;提出了猎人猎物算法&#xff08;Hunter-Prey Optimization&#xff0c; HPO&#xff09;。 2.算法原理 2.1算法思想 HPO模拟…

输出1到10的阶乘--C语言

#include<stdio.h> int fac(int n){if(n<1){return 1;}elsereturn fac(n-1)*n; } int main(){int i, result;for(i1;i<10;i){resultfac(i);printf("%d!%d\n",i,result);}} 输出结果&#xff1a;

Java并发编程基础_Thread类

线程 Thread.class 1. 线程的六种状态 NEW 尚未启动的线程处于此状态。RUNNABLE 在Java虚拟机中执行的线程处于此状态。BLOCKED 被阻塞等待监视器锁定的线程处于此状态。WAITING 正在等待另一个线程执行特定动作的线程处于此状态。TIMED_WAITING 正在等待另一个线程执行动作达到…

C++中浅拷贝和深拷贝对象复制概念

1.浅拷贝&#xff08;Shallow Copy&#xff09;&#xff1a; 浅拷贝是指在对象复制时&#xff0c;只是复制对象的值&#xff0c;而不会复制对象指向的资源。这意味着对象和其副本会指向同一块内存空间&#xff0c;当一个对象改变时&#xff0c;另一个对象也会受到影响。 #inclu…

中国电子学会(CEIT)2021年09月真题C语言软件编程等级考试四级(含详细解析答案)

中国电子学会&#xff08;CEIT&#xff09;考评中心历届真题&#xff08;含解析答案&#xff09; C语言软件编程等级考试四级 2021年09月 编程题四道 总分:100分一、吃奶酪&#xff08;25分&#xff09; Jerry准备偷吃Tom的奶酪。所有的奶酪排成了一条直线&#xff0c;…

回溯算法|216.组合总和III

力扣题目链接 class Solution { private:vector<vector<int>> result; // 存放结果集vector<int> path; // 符合条件的结果// targetSum&#xff1a;目标和&#xff0c;也就是题目中的n。// k&#xff1a;题目中要求k个数的集合。// sum&#xff1a;已经收集…

OpenKylin安装Kafka

一、操作系统 openKylin 1.0.1 X86 二、下载安装包 # 安装依赖jdk sudo apt-get update sudo apt-get install default-jdk # 下载kafka mkdir -p /data/software/kafka wget https://archive.apache.org/dist/kafka/2.4.1/kafka_2.13-2.4.1.tgz三、解压安装 # 解压缩Kafka…

springboot项目学习-瑞吉外卖(4)续

1.任务 菜品的添加功能(涉及到两张表的数据添加) 2.菜品添加 功能页面如上&#xff0c;该页面有两个注意点 菜品分类&#xff1a;点击菜品分类后&#xff0c;会展示当前已有菜品&#xff1a;这个功能的实现要从category表里查询数据&#xff0c;然后再做展示口味做法配置&#…

算法题->移动零的C语言和JAVA的双指针解法

使用C语言和JAVA代码通过双指针进行解题 题目描述:给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 理解题意:不改变数组中非零元素的顺序,并把0元素放在非零元素后面. 链接: https://leetcode.cn/problems/m…

Linux——将云服务器作为跳板机,frp实现内网穿透

文章目录 操作步骤1. 准备工作&#xff1a;2. 配置frp服务器端&#xff1a;3. 配置frp客户端&#xff1a;4. 启动frp客户端&#xff1a;5. 测试连接&#xff1a;6. 安全注意事项&#xff1a; 云服务器性能分析阿里云具体操作步骤1. 购买&#xff1a;2. 登录&#xff1a;3. 首次…

【springboot】闲话 springboot 的几种异步机制 及 长轮询的概念和简单实现

文章目录 引子springboot的几种异步形式开启异步支持和线程池配置&#xff08;重要&#xff09;第一种&#xff1a;Async第二种&#xff1a;Callable<T>第三种&#xff1a;WebAsyncTask<T>第四种&#xff1a;DeferredResult<T> 长轮询的简单实现概念实现服务…

spring boot-引入Redis并封装redistemplate操作工具类

文章目录 一、关于spring-redis二、springboot引入Redis及其使用案例三、封装redistemplate操作工具类 一、关于spring-redis spring-data-redis针对jedis提供了如下功能&#xff1a; 连接池自动管理&#xff0c;提供了一个高度封装的“RedisTemplate”类 针对jedis客户端中大…

设置 Linux 时间同步 同步硬件时钟

设置 Linux 时间同步 同步硬件时钟 配置 NTP 客户端查看当前系统时间使用 ntpdate 命令手动同步时间同步硬件时钟再次检查硬件时钟参考 配置 NTP 客户端 vim /etc/systemd/timesyncd.conf[Time] NTPcn.pool.ntp.org FallbackNTPasia.pool.ntp.org ntp.aliyun.com ntp1.aliyun.…

acwing算法提高之图论--单源最短路的扩展应用

目录 1 介绍2 训练 1 介绍 本专题用来记录使用。。。。 2 训练 题目1&#xff1a;1137选择最佳线路 C代码如下&#xff0c; #include <iostream> #include <cstring> #include <algorithm> #include <queue>using namespace std;const int N 101…