鸿蒙(HarmoneyOS),封装一个通用关系型数据库操作类
ts
import { relationalStore } from '@kit.ArkData';
import { BusinessError } from '@kit.BasicServicesKit';
import { LogUtil } from '../util/LogUtil';
import { GlobalContext } from '../util/GlobalContext';
const TAG = 'RdbHelper';
/**
* 数据库升级回调类型
* @param oldVersion 当前旧版本号
* @param store RdbStore实例,可直接执行升级SQL
*/
export type UpgradeCallback = (oldVersion: number, transaction: relationalStore.Transaction) => Promise<void>;
/**
* 数据库首次创建回调类型
* @param store RdbStore实例,用于执行建表SQL
*/
export type CreateCallback = (transaction: relationalStore.Transaction) => Promise<void>;
/**
* 查询结果行类型,键为列名,值为对应列的值
*/
export type QueryRow = Record<string, relationalStore.ValueType>;
/**
* 关系型数据库通用工具类
*
* 功能特性:
* 1. 默认数据库名称为 XXXXXX.db
* 2. 支持基于 user_version 的数据库版本升级
* 3. 提供完整的增删改查接口
* 4. 内置事务支持
*/
export class RdbHelper {
private static readonly DEFAULT_DB_NAME = 'XXXXXX.db';
private static instance: RdbHelper | null = null;
private rdbStore: relationalStore.RdbStore | null = null;
private dbName: string;
private initialized: boolean = false;
private constructor(dbName: string = RdbHelper.DEFAULT_DB_NAME) {
this.dbName = dbName;
}
/**
* 获取单例实例
* @param dbName 可选,自定义数据库名称,仅在首次调用时生效
*/
static getInstance(dbName?: string): RdbHelper {
if (!RdbHelper.instance) {
RdbHelper.instance = new RdbHelper(dbName ?? RdbHelper.DEFAULT_DB_NAME);
}
return RdbHelper.instance;
}
/**
* 释放单例(通常用于测试场景或需要重新初始化时调用)
*/
static releaseInstance(): void {
if (RdbHelper.instance) {
RdbHelper.instance.rdbStore = null;
RdbHelper.instance.initialized = false;
}
RdbHelper.instance = null;
}
/**
* 初始化数据库,自动处理创建及版本升级
*
* @param targetVersion 目标数据库版本号(大于0的整数)
* @param onCreate 数据库首次创建时的回调,用于执行建表语句
* @param onUpgrade 数据库升级回调,参数为当前旧版本号
*/
async initDatabase(targetVersion: number, onCreate?: CreateCallback,
onUpgrade?: UpgradeCallback): Promise<void> {
if (this.initialized && this.rdbStore) {
LogUtil.info(TAG, 'Database already initialized, skip.');
return;
}
// 检查分词器支持
let tokenType = relationalStore.Tokenizer.ICU_TOKENIZER;
let tokenizerSupported = relationalStore.isTokenizerSupported(tokenType);
if (!tokenizerSupported) {
tokenType = relationalStore.Tokenizer.NONE_TOKENIZER;
LogUtil.info(TAG, 'ICU_TOKENIZER is not supported on this platform, use NONE_TOKENIZER.');
}
const config: relationalStore.StoreConfig = {
name: this.dbName,
securityLevel: relationalStore.SecurityLevel.S3,
encrypt: false,
isReadOnly: false,
tokenizer: tokenType
};
try {
this.rdbStore = await relationalStore.getRdbStore(GlobalContext.getContext(), config);
LogUtil.info(TAG, `Succeeded in getting RdbStore: ${this.dbName}`);
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `Failed to get RdbStore. Code:${error.code}, message:${error.message}`);
throw new Error(`Failed to get RdbStore: ${error.message}`);
}
// 处理数据库版本
await this.handleVersionUpgrade(targetVersion, onCreate, onUpgrade);
this.initialized = true;
LogUtil.info(TAG, `Database initialized successfully, version: ${targetVersion}`);
}
/**
* 处理数据库版本升级逻辑
*/
private async handleVersionUpgrade(targetVersion: number, onCreate?: CreateCallback,
onUpgrade?: UpgradeCallback): Promise<void> {
if (!this.rdbStore) {
throw new Error('RdbStore is not initialized');
}
let transaction: relationalStore.Transaction | null = null;
try {
transaction = await this.rdbStore.createTransaction({});
let currentVersion = await this.fetchStoreVersion(transaction);
LogUtil.info(TAG, `Current DB version: ${currentVersion}, Target version: ${targetVersion}`);
if (currentVersion === 0) {
// 数据库首次创建
if (onCreate) {
await onCreate(transaction);
}
await transaction.execute(`PRAGMA user_version = ${targetVersion}`);
LogUtil.info(TAG, `Database created, set version to ${targetVersion}.`);
} else if (currentVersion < targetVersion) {
// 需要逐级升级
if (onUpgrade) {
for (let ver = currentVersion; ver < targetVersion; ver++) {
LogUtil.info(TAG, `Upgrading database from version ${ver} to ${ver + 1}.`);
await onUpgrade(ver, transaction);
}
}
await transaction.execute(`PRAGMA user_version = ${targetVersion}`);
LogUtil.info(TAG, `Database upgraded to version ${targetVersion}.`);
} else if (currentVersion > targetVersion) {
LogUtil.warn(TAG,
`Current version ${currentVersion} is higher than target ${targetVersion}, skip upgrade.`);
}
await transaction.commit();
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `Failed during version upgrade. Code:${error.code}, message:${error.message}`);
if (transaction) {
try {
await transaction.rollback();
} catch (rollbackErr) {
LogUtil.error(TAG, `Rollback failed: ${(rollbackErr as BusinessError).message}`);
}
}
throw new Error(`Database upgrade failed: ${error.message}`);
}
}
/**
* 通过事务查询当前数据库版本号
*/
private async fetchStoreVersion(transaction: relationalStore.Transaction): Promise<number> {
let storeVersion = await transaction.execute('PRAGMA user_version');
return storeVersion as number;
}
// ==================== 内部校验 ====================
/**
* 确保数据库已初始化,返回 RdbStore 实例
*/
private ensureInitialized(): relationalStore.RdbStore {
if (!this.rdbStore) {
throw new Error('Database not initialized. Please call initDatabase() first.');
}
return this.rdbStore;
}
// ==================== CRUD 操作 ====================
/**
* 插入单条数据
*
* @param table 表名
* @param values 待插入的键值对数据
* @returns 插入行的 rowId,失败时返回 -1
*/
async insert(table: string, values: relationalStore.ValuesBucket): Promise<number> {
let store = this.ensureInitialized();
try {
let rowId = await store.insert(table, values);
LogUtil.info(TAG, `Insert into '${table}' success, rowId: ${rowId}`);
return rowId;
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `Insert into '${table}' failed. Code:${error.code}, message:${error.message}`);
throw new Error(`Insert failed: ${error.message}`);
}
}
/**
* 批量插入数据
*
* @param table 表名
* @param valuesList 待插入的键值对数据列表
* @returns 实际插入的行数
*/
async batchInsert(table: string, valuesList: relationalStore.ValuesBucket[]): Promise<number> {
let store = this.ensureInitialized();
try {
let count = await store.batchInsert(table, valuesList);
LogUtil.info(TAG, `Batch insert into '${table}' success, count: ${count}`);
return count;
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `Batch insert into '${table}' failed. Code:${error.code}, message:${error.message}`);
throw new Error(`Batch insert failed: ${error.message}`);
}
}
/**
* 根据条件删除数据
*
* @param predicates 删除条件(需指定表名)
* @returns 删除的行数
*/
async delete(predicates: relationalStore.RdbPredicates): Promise<number> {
let store = this.ensureInitialized();
try {
let count = await store.delete(predicates);
LogUtil.info(TAG, `Delete success, count: ${count}`);
return count;
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `Delete failed. Code:${error.code}, message:${error.message}`);
throw new Error(`Delete failed: ${error.message}`);
}
}
/**
* 根据条件更新数据
*
* @param values 待更新的键值对数据
* @param predicates 更新条件(需指定表名)
* @returns 更新的行数
*/
async update(values: relationalStore.ValuesBucket, predicates: relationalStore.RdbPredicates): Promise<number> {
let store = this.ensureInitialized();
try {
let count = await store.update(values, predicates);
LogUtil.info(TAG, `Update success, count: ${count}`);
return count;
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `Update failed. Code:${error.code}, message:${error.message}`);
throw new Error(`Update failed: ${error.message}`);
}
}
/**
* 查询多条数据
*
* @param predicates 查询条件(需指定表名)
* @param columns 要查询的列名数组,不传则查询所有列
* @returns 查询结果列表
*/
async query(predicates: relationalStore.RdbPredicates, columns?: string[]): Promise<QueryRow[]> {
let store = this.ensureInitialized();
let resultSet: relationalStore.ResultSet | null = null;
try {
resultSet = await store.query(predicates, columns);
let results: QueryRow[] = [];
let columnNames = resultSet.columnNames;
while (resultSet.goToNextRow()) {
let row: QueryRow = {};
for (let col of columnNames) {
let colIdx = resultSet.getColumnIndex(col);
row[col] = await this.getValueFromResultSet(resultSet, colIdx);
}
results.push(row);
}
return results;
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `Query failed. Code:${error.code}, message:${error.message}`);
throw new Error(`Query failed: ${error.message}`);
} finally {
if (resultSet) {
resultSet.close();
}
}
}
/**
* 查询单条数据
*
* @param predicates 查询条件(需指定表名)
* @param columns 要查询的列名数组,不传则查询所有列
* @returns 查询结果行,未找到返回 null
*/
async queryOne(predicates: relationalStore.RdbPredicates, columns?: string[]): Promise<QueryRow | null> {
let store = this.ensureInitialized();
let resultSet: relationalStore.ResultSet | null = null;
try {
resultSet = await store.query(predicates, columns);
if (resultSet.goToFirstRow()) {
let row: QueryRow = {};
let columnNames = resultSet.columnNames;
for (let col of columnNames) {
let colIdx = resultSet.getColumnIndex(col);
row[col] = await this.getValueFromResultSet(resultSet, colIdx);
}
return row;
}
return null;
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `QueryOne failed. Code:${error.code}, message:${error.message}`);
throw new Error(`QueryOne failed: ${error.message}`);
} finally {
if (resultSet) {
resultSet.close();
}
}
}
/**
* 查询记录总数
*
* @param predicates 查询条件(需指定表名)
* @returns 匹配的记录数
*/
async count(predicates: relationalStore.RdbPredicates): Promise<number> {
let store = this.ensureInitialized();
let resultSet: relationalStore.ResultSet | null = null;
try {
resultSet = await store.query(predicates, ['COUNT(*) AS cnt']);
if (resultSet.goToFirstRow()) {
let colIdx = resultSet.getColumnIndex('cnt');
return resultSet.getLong(colIdx);
}
return 0;
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `Count failed. Code:${error.code}, message:${error.message}`);
throw new Error(`Count failed: ${error.message}`);
} finally {
if (resultSet) {
resultSet.close();
}
}
}
/**
* 执行非查询 SQL 语句(INSERT / UPDATE / DELETE / DDL 等)
*
* @param sql SQL 语句
* @param bindArgs 绑定参数(与 ? 占位符一一对应)
*/
async executeSql(sql: string, bindArgs?: relationalStore.ValueType[]): Promise<void> {
let store = this.ensureInitialized();
try {
await store.executeSql(sql, bindArgs);
LogUtil.info(TAG, 'Execute SQL success.');
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `Execute SQL failed. Code:${error.code}, message:${error.message}`);
throw new Error(`Execute SQL failed: ${error.message}`);
}
}
/**
* 执行查询 SQL 语句
*
* @param sql 查询 SQL 语句
* @param bindArgs 绑定参数(与 ? 占位符一一对应)
* @returns 查询结果列表
*/
async querySql(sql: string, bindArgs?: relationalStore.ValueType[]): Promise<QueryRow[]> {
let store = this.ensureInitialized();
let resultSet: relationalStore.ResultSet | null = null;
try {
resultSet = await store.querySql(sql, bindArgs);
let results: QueryRow[] = [];
let columnNames = resultSet.columnNames;
while (resultSet.goToNextRow()) {
let row: QueryRow = {};
for (let col of columnNames) {
let colIdx = resultSet.getColumnIndex(col);
row[col] = await this.getValueFromResultSet(resultSet, colIdx);
}
results.push(row);
}
return results;
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `Query SQL failed. Code:${error.code}, message:${error.message}`);
throw new Error(`Query SQL failed: ${error.message}`);
} finally {
if (resultSet) {
resultSet.close();
}
}
}
/**
* 从 ResultSet 中根据列类型安全地提取值
*/
private async getValueFromResultSet(resultSet: relationalStore.ResultSet, columnIndex: number): Promise<relationalStore.ValueType> {
if (resultSet.isColumnNull(columnIndex)) {
return '';
}
let columnType = await resultSet.getColumnType(columnIndex);
switch (columnType) {
case relationalStore.ColumnType.INTEGER:
return resultSet.getLong(columnIndex);
case relationalStore.ColumnType.FLOAT_VECTOR:
return resultSet.getDouble(columnIndex);
case relationalStore.ColumnType.TEXT:
return resultSet.getString(columnIndex);
case relationalStore.ColumnType.BLOB:
return resultSet.getBlob(columnIndex);
default:
return resultSet.getString(columnIndex);
}
}
// ==================== 事务操作 ====================
/**
* 在事务中执行操作,自动 commit / rollback
*
* @param action 事务内要执行的操作,回调参数为当前 RdbStore 实例
*
* 使用示例:
* ```
* await helper.runInTransaction(async (store) => {
* await store.executeSql('INSERT INTO ...');
* await store.executeSql('UPDATE ...');
* });
* ```
*/
async runInTransaction(action: (store: relationalStore.RdbStore) => Promise<void>): Promise<void> {
let store = this.ensureInitialized();
let transaction: relationalStore.Transaction | null = null;
try {
transaction = await store.createTransaction({});
await action(store);
await transaction.commit();
LogUtil.info(TAG, 'Transaction committed successfully.');
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `Transaction failed. Code:${error.code}, message:${error.message}`);
if (transaction) {
try {
await transaction.rollback();
LogUtil.info(TAG, 'Transaction rolled back.');
} catch (rollbackErr) {
LogUtil.error(TAG, `Rollback failed: ${(rollbackErr as BusinessError).message}`);
}
}
throw new Error(`Transaction failed: ${error.message}`);
}
}
// ==================== 工具方法 ====================
/**
* 获取原始 RdbStore 实例,用于直接调用原生 API
*/
getRawStore(): relationalStore.RdbStore | null {
return this.rdbStore;
}
/**
* 获取当前数据库名称
*/
getDatabaseName(): string {
return this.dbName;
}
/**
* 检查数据库是否已初始化
*/
isInitialized(): boolean {
return this.initialized && this.rdbStore !== null;
}
/**
* 关闭数据库(清除实例引用)
*/
async close(): Promise<void> {
this.rdbStore = null;
this.initialized = false;
LogUtil.info(TAG, 'Database store reference cleared.');
}
/**
* 删除数据库文件
* 注意:调用前请确保没有正在进行的数据库操作
*/
async deleteDatabase(): Promise<void> {
await this.close();
try {
await relationalStore.deleteRdbStore(GlobalContext.getContext(), this.dbName);
LogUtil.info(TAG, `Database '${this.dbName}' deleted.`);
} catch (err) {
let error = err as BusinessError;
LogUtil.error(TAG, `Failed to delete database. Code:${error.code}, message:${error.message}`);
throw new Error(`Delete database failed: ${error.message}`);
}
}
}
使用示例
ts
const TAG = 'AppDBController';
export class AppDBController {
private static readonly DB_VERSION = 1;
private static instance: AppDBController;
private helper: RdbHelper;
private constructor() {
this.helper = RdbHelper.getInstance();
}
public static getInstance(): AppDBController {
if (!AppDBController.instance) {
AppDBController.instance = new AppDBController();
}
return AppDBController.instance;
}
/**
* 初始化数据库(首次创建建全部表,后续按版本升级)
*/
async init(): Promise<void> {
await this.helper.initDatabase(
AppDBController.DB_VERSION,
// onCreate:首次创建时建表
LogUtil.info(TAG, `Table ${AppRecord.TABLE_NAME} created.`);
},
// onUpgrade:逐级升级
async (oldVersion: number, transaction: relationalStore.Transaction) => {
// v2 -> v3:新增 XXX
/*if (oldVersion === 2) {
await transaction.execute(``);
}*/
}
);
}
}