HarmonyOS 5开发从入门到精通(八):本地数据存储与持久化
数据持久化是移动应用开发的核心能力,确保应用数据在设备重启或应用关闭后仍能保留。HarmonyOS 5提供了多种数据持久化方案,从轻量级的键值对存储到复杂的关系型数据库,满足不同场景的需求。本篇将深入讲解本地数据存储的实现、优化和实战应用。
一、数据持久化方案概览
1.1 三种主要存储方式对比
| 特性 | Preferences | KV-Store | RelationalStore |
|---|---|---|---|
| 数据模型 | 键值对 | 键值对 | 关系型表 |
| 查询能力 | 简单 | 简单 | 复杂SQL查询 |
| 适合数据量 | <1MB | <10MB | 无限制 |
| 跨设备同步 | 不支持 | 支持 | 支持 |
| 事务支持 | 不支持 | 有限支持 | 完整支持 |
选择建议:
- 用户配置:Preferences
- 应用缓存:KV-Store
- 结构化业务数据:RelationalStore
- 需要跨设备同步的数据:KV-Store或RelationalStore
二、用户首选项(Preferences)
2.1 基本使用
Preferences是最轻量级的键值对存储方案,适合保存少量配置信息。
import preferences from '@ohos.data.preferences';
import { BusinessError } from '@ohos.base';// 创建Preferences实例
let prefs: preferences.Preferences | null = null;async function initPreferences() {try {const context = getContext(this);prefs = await preferences.getPreferences(context, 'user_settings');console.info('Preferences初始化成功');} catch (error) {console.error(`Preferences初始化失败: ${(error as BusinessError).message}`);}
}// 存储数据
async function saveData(key: string, value: string) {if (!prefs) return;await prefs.put(key, value);await prefs.flush(); // 持久化到文件
}// 读取数据
async function getData(key: string, defaultValue: string = ''): Promise<string> {if (!prefs) return defaultValue;return await prefs.get(key, defaultValue);
}
2.2 封装工具类
// utils/preferences.ts
import preferences from '@ohos.data.preferences';
import { BusinessError } from '@ohos.base';class PreferencesManager {private static instance: PreferencesManager;private prefs: preferences.Preferences | null = null;private context: any;static getInstance(context: any): PreferencesManager {if (!PreferencesManager.instance) {PreferencesManager.instance = new PreferencesManager(context);}return PreferencesManager.instance;}private constructor(context: any) {this.context = context;}async init(storeName: string = 'default'): Promise<void> {try {this.prefs = await preferences.getPreferences(this.context, storeName);} catch (error) {console.error(`Preferences初始化失败: ${(error as BusinessError).message}`);}}async setString(key: string, value: string): Promise<void> {if (!this.prefs) return;await this.prefs.put(key, value);await this.prefs.flush();}async getString(key: string, defaultValue: string = ''): Promise<string> {if (!this.prefs) return defaultValue;return await this.prefs.get(key, defaultValue);}async setNumber(key: string, value: number): Promise<void> {await this.setString(key, value.toString());}async getNumber(key: string, defaultValue: number = 0): Promise<number> {const value = await this.getString(key);return value ? parseInt(value) : defaultValue;}async setBoolean(key: string, value: boolean): Promise<void> {await this.setString(key, value ? 'true' : 'false');}async getBoolean(key: string, defaultValue: boolean = false): Promise<boolean> {const value = await this.getString(key);return value ? value === 'true' : defaultValue;}async remove(key: string): Promise<void> {if (!this.prefs) return;await this.prefs.delete(key);await this.prefs.flush();}async clear(): Promise<void> {if (!this.prefs) return;await this.prefs.clear();await this.prefs.flush();}
}export default PreferencesManager;
三、关系型数据库(RelationalStore)
3.1 数据库创建与表结构定义
import relationalStore from '@ohos.data.relationalStore';
import { BusinessError } from '@ohos.base';// 定义表结构
const SQL_CREATE_TABLE = `
CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT NOT NULL,email TEXT UNIQUE,age INTEGER,created_at INTEGER DEFAULT (strftime('%s', 'now'))
)
`;// 数据库配置
const STORE_CONFIG: relationalStore.StoreConfig = {name: 'app_database.db',securityLevel: relationalStore.SecurityLevel.S2,encrypt: true
};class DatabaseManager {private rdbStore: relationalStore.RdbStore | null = null;private context: any;constructor(context: any) {this.context = context;}async init(): Promise<void> {try {this.rdbStore = await relationalStore.getRdbStore(this.context, STORE_CONFIG);await this.rdbStore.executeSql(SQL_CREATE_TABLE);console.info('数据库初始化成功');} catch (error) {console.error(`数据库初始化失败: ${(error as BusinessError).message}`);}}// 插入数据async insertUser(name: string, email: string, age: number): Promise<number> {if (!this.rdbStore) return -1;const valuesBucket: relationalStore.ValuesBucket = {'name': name,'email': email,'age': age};try {const result = await this.rdbStore.insert('users', valuesBucket);return result;} catch (error) {console.error(`插入数据失败: ${(error as BusinessError).message}`);return -1;}}// 查询数据async queryUsers(): Promise<any[]> {if (!this.rdbStore) return [];const predicates = new relationalStore.RdbPredicates('users');const columns = ['id', 'name', 'email', 'age', 'created_at'];try {const resultSet = await this.rdbStore.query(predicates, columns);const users: any[] = [];while (resultSet.goToNextRow()) {users.push({id: resultSet.getLong(resultSet.getColumnIndex('id')),name: resultSet.getString(resultSet.getColumnIndex('name')),email: resultSet.getString(resultSet.getColumnIndex('email')),age: resultSet.getLong(resultSet.getColumnIndex('age')),created_at: resultSet.getLong(resultSet.getColumnIndex('created_at'))});}resultSet.close();return users;} catch (error) {console.error(`查询数据失败: ${(error as BusinessError).message}`);return [];}}// 更新数据async updateUser(id: number, name: string, email: string, age: number): Promise<number> {if (!this.rdbStore) return 0;const predicates = new relationalStore.RdbPredicates('users');predicates.equalTo('id', id);const valuesBucket: relationalStore.ValuesBucket = {'name': name,'email': email,'age': age};try {const result = await this.rdbStore.update(valuesBucket, predicates);return result;} catch (error) {console.error(`更新数据失败: ${(error as BusinessError).message}`);return 0;}}// 删除数据async deleteUser(id: number): Promise<number> {if (!this.rdbStore) return 0;const predicates = new relationalStore.RdbPredicates('users');predicates.equalTo('id', id);try {const result = await this.rdbStore.delete(predicates);return result;} catch (error) {console.error(`删除数据失败: ${(error as BusinessError).message}`);return 0;}}// 事务操作async executeTransaction(operations: (() => Promise<void>)[]): Promise<void> {if (!this.rdbStore) return;try {await this.rdbStore.beginTransaction();for (const operation of operations) {await operation();}await this.rdbStore.commit();} catch (error) {await this.rdbStore.rollBack();console.error(`事务执行失败: ${(error as BusinessError).message}`);throw error;}}
}export default DatabaseManager;
3.2 复杂查询示例
// 条件查询
async function queryUsersByCondition(): Promise<any[]> {if (!this.rdbStore) return [];const predicates = new relationalStore.RdbPredicates('users');predicates.equalTo('age', 25) // age = 25.greaterThan('created_at', Date.now() - 7 * 24 * 60 * 60 * 1000) // 最近7天.orderByAsc('name') // 按姓名升序.limit(10); // 限制10条const columns = ['id', 'name', 'email', 'age'];try {const resultSet = await this.rdbStore.query(predicates, columns);const users: any[] = [];while (resultSet.goToNextRow()) {users.push({id: resultSet.getLong(resultSet.getColumnIndex('id')),name: resultSet.getString(resultSet.getColumnIndex('name')),email: resultSet.getString(resultSet.ColumnIndex('email')),age: resultSet.getLong(resultSet.getColumnIndex('age'))});}resultSet.close();return users;} catch (error) {console.error(`条件查询失败: ${(error as BusinessError).message}`);return [];}
}// 聚合查询
async function getStatistics(): Promise<any> {if (!this.rdbStore) return null;const sql = `SELECT COUNT(*) as total_users,AVG(age) as avg_age,MAX(age) as max_age,MIN(age) as min_ageFROM users`;try {const resultSet = await this.rdbStore.executeSql(sql);const stats: any = {};if (resultSet.goToNextRow()) {stats.total_users = resultSet.getLong(resultSet.getColumnIndex('total_users'));stats.avg_age = resultSet.getDouble(resultSet.getColumnIndex('avg_age'));stats.max_age = resultSet.getLong(resultSet.getColumnIndex('max_age'));stats.min_age = resultSet.getLong(resultSet.getColumnIndex('min_age'));}resultSet.close();return stats;} catch (error) {console.error(`聚合查询失败: ${(error as BusinessError).message}`);return null;}
}
四、文件存储(FileIO)
4.1 文件读写操作
import fileio from '@ohos.fileio';
import { BusinessError } from '@ohos.base';class FileManager {private context: any;constructor(context: any) {this.context = context;}// 写入文本文件async writeTextFile(filePath: string, content: string): Promise<boolean> {try {const fd = await fileio.open(filePath, fileio.OpenMode.CREATE | fileio.OpenMode.WRITE_ONLY);const buffer = new ArrayBuffer(content.length * 2);const encoder = new TextEncoder();const encoded = encoder.encode(content);await fileio.write(fd, encoded.buffer, { offset: 0 });await fileio.close(fd);return true;} catch (error) {console.error(`写入文件失败: ${(error as BusinessError).message}`);return false;}}// 读取文本文件async readTextFile(filePath: string): Promise<string> {try {const fd = await fileio.open(filePath, fileio.OpenMode.READ_ONLY);const stat = await fileio.stat(fd);const buffer = new ArrayBuffer(stat.size);await fileio.read(fd, buffer, { offset: 0 });await fileio.close(fd);const decoder = new TextDecoder('utf-8');return decoder.decode(new Uint8Array(buffer));} catch (error) {console.error(`读取文件失败: ${(error as BusinessError).message}`);return '';}}// 创建目录async createDirectory(dirPath: string): Promise<boolean> {try {await fileio.mkdir(dirPath);return true;} catch (error) {console.error(`创建目录失败: ${(error as BusinessError).message}`);return false;}}// 检查文件是否存在async fileExists(filePath: string): Promise<boolean> {try {await fileio.access(filePath);return true;} catch (error) {return false;}}// 删除文件async deleteFile(filePath: string): Promise<boolean> {try {await fileio.unlink(filePath);return true;} catch (error) {console.error(`删除文件失败: ${(error as BusinessError).message}`);return false;}}// 获取文件列表async listFiles(dirPath: string): Promise<string[]> {try {const files = await fileio.listFile(dirPath);return files;} catch (error) {console.error(`获取文件列表失败: ${(error as BusinessError).message}`);return [];}}
}export default FileManager;
4.2 文件缓存管理
// utils/fileCache.ts
import fileio from '@ohos.fileio';
import { BusinessError } from '@ohos.base';interface CacheItem {key: string;value: string;timestamp: number;ttl: number; // 缓存有效时间(毫秒)
}class FileCacheManager {private cacheDir: string;private memoryCache: Map<string, CacheItem> = new Map();constructor(context: any) {this.cacheDir = context.cacheDir + '/file_cache';this.initCacheDir();}private async initCacheDir(): Promise<void> {try {await fileio.mkdir(this.cacheDir);} catch (error) {// 目录已存在或其他错误}}// 设置缓存async set(key: string, value: string, ttl: number = 24 * 60 * 60 * 1000): Promise<void> {const cacheItem: CacheItem = {key,value,timestamp: Date.now(),ttl};// 内存缓存this.memoryCache.set(key, cacheItem);// 文件缓存const filePath = `${this.cacheDir}/${key}.json`;const content = JSON.stringify(cacheItem);try {const fd = await fileio.open(filePath, fileio.OpenMode.CREATE | fileio.OpenMode.WRITE_ONLY);const encoder = new TextEncoder();const encoded = encoder.encode(content);await fileio.write(fd, encoded.buffer, { offset: 0 });await fileio.close(fd);} catch (error) {console.error(`缓存写入失败: ${(error as BusinessError).message}`);}}// 获取缓存async get(key: string): Promise<string | null> {// 检查内存缓存const memoryItem = this.memoryCache.get(key);if (memoryItem && Date.now() - memoryItem.timestamp < memoryItem.ttl) {return memoryItem.value;}// 检查文件缓存const filePath = `${this.cacheDir}/${key}.json`;try {const fd = await fileio.open(filePath, fileio.OpenMode.READ_ONLY);const stat = await fileio.stat(fd);const buffer = new ArrayBuffer(stat.size);await fileio.read(fd, buffer, { offset: 0 });await fileio.close(fd);const decoder = new TextDecoder('utf-8');const content = decoder.decode(new Uint8Array(buffer));const cacheItem: CacheItem = JSON.parse(content);// 检查是否过期if (Date.now() - cacheItem.timestamp > cacheItem.ttl) {await this.delete(key);return null;}// 更新内存缓存this.memoryCache.set(key, cacheItem);return cacheItem.value;} catch (error) {return null;}}// 删除缓存async delete(key: string): Promise<void> {this.memoryCache.delete(key);const filePath = `${this.cacheDir}/${key}.json`;try {await fileio.unlink(filePath);} catch (error) {// 文件不存在或其他错误}}// 清理过期缓存async cleanup(): Promise<void> {try {const files = await fileio.listFile(this.cacheDir);for (const file of files) {const filePath = `${this.cacheDir}/${file}`;const fd = await fileio.open(filePath, fileio.OpenMode.READ_ONLY);const stat = await fileio.stat(fd);const buffer = new ArrayBuffer(stat.size);await fileio.read(fd, buffer, { offset: 0 });await fileio.close(fd);const decoder = new TextDecoder('utf-8');const content = decoder.decode(new Uint8Array(buffer));const cacheItem: CacheItem = JSON.parse(content);if (Date.now() - cacheItem.timestamp > cacheItem.ttl) {await fileio.unlink(filePath);}}} catch (error) {console.error(`清理缓存失败: ${(error as BusinessError).message}`);}}
}export default FileCacheManager;
五、数据加密与安全
5.1 敏感数据加密存储
import huks from '@ohos.UniversalKeystoreKit';
import { util } from '@ohos.ArkTS';
import { BusinessError } from '@ohos.base';class EncryptionManager {private keyAlias: string = 'app_encryption_key';// 生成加密密钥async generateKey(): Promise<void> {const properties: huks.HuksParam[] = [{tag: huks.HuksTag.HUKS_TAG_ALGORITHM,value: huks.HuksKeyAlg.HUKS_ALG_AES},{tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256},{tag: huks.HuksTag.HUKS_TAG_PURPOSE,value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT}];const options: huks.HuksOptions = { properties };try {await huks.generateKeyItem(this.keyAlias, options);console.info('加密密钥生成成功');} catch (error) {console.error(`加密密钥生成失败: ${(error as BusinessError).message}`);}}// 加密数据async encryptData(data: string): Promise<string> {const properties: huks.HuksParam[] = [{tag: huks.HuksTag.HUKS_TAG_ALGORITHM,value: huks.HuksKeyAlg.HUKS_ALG_AES},{tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256},{tag: huks.HuksTag.HUKS_TAG_PURPOSE,value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT},{tag: huks.HuksTag.HUKS_TAG_PADDING,value: huks.HuksPadding.HUKS_PADDING_PKCS7},{tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,value: huks.HuksBlockMode.HUKS_BLOCK_MODE_CBC}];const encoder = new TextEncoder();const inData = encoder.encode(data);const options: huks.HuksOptions = {properties,inData};try {const handleObj = await huks.initSession(this.keyAlias, options);const result = await huks.finishSession(handleObj.handle, options);const base64Helper = new util.Base64Helper();return base64Helper.encodeToStringSync(result.outData as Uint8Array);} catch (error) {console.error(`数据加密失败: ${(error as BusinessError).message}`);throw error;}}// 解密数据async decryptData(encryptedData: string): Promise<string> {const properties: huks.HuksParam[] = [{tag: huks.HuksTag.HUKS_TAG_ALGORITHM,value: huks.HuksKeyAlg.HUKS_ALG_AES},{tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256},{tag: huks.HuksTag.HUKS_TAG_PURPOSE,value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT},{tag: huks.HuksTag.HUKS_TAG_PADDING,value: huks.HuksPadding.HUKS_PADDING_PKCS7},{tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,value: huks.HuksBlockMode.HUKS_BLOCK_MODE_CBC}];const base64Helper = new util.Base64Helper();const inData = base64Helper.decodeSync(encryptedData);const options: huks.HuksOptions = {properties,inData};try {const handleObj = await huks.initSession(this.keyAlias, options);const result = await huks.finishSession(handleObj.handle, options);const decoder = new TextDecoder('utf-8');return decoder.decode(result.outData as Uint8Array);} catch (error) {console.error(`数据解密失败: ${(error as BusinessError).message}`);throw error;}}
}export default EncryptionManager;
5.2 安全的用户首选项存储
// utils/securePreferences.ts
import PreferencesManager from './preferences';
import EncryptionManager from './encryptionManager';class SecurePreferencesManager {private preferences: PreferencesManager;private encryption: EncryptionManager;constructor(context: any) {this.preferences = PreferencesManager.getInstance(context);this.encryption = new EncryptionManager();}async init(): Promise<void> {await this.preferences.init('secure_store');await this.encryption.generateKey();}async setSecureString(key: string, value: string): Promise<void> {const encryptedValue = await this.encryption.encryptData(value);await this.preferences.setString(key, encryptedValue);}async getSecureString(key: string, defaultValue: string = ''): Promise<string> {const encryptedValue = await this.preferences.getString(key);if (!encryptedValue) return defaultValue;try {return await this.encryption.decryptData(encryptedValue);} catch (error) {console.error(`解密数据失败: ${(error as BusinessError).message}`);return defaultValue;}}async setSecureNumber(key: string, value: number): Promise<void> {await this.setSecureString(key, value.toString());}async getSecureNumber(key: string, defaultValue: number = 0): Promise<number> {const value = await this.getSecureString(key);return value ? parseInt(value) : defaultValue;}
}export default SecurePreferencesManager;
六、数据迁移与升级
6.1 数据库版本升级
// 数据库升级回调
const onUpgrade = async (rdbStore: relationalStore.RdbStore, oldVersion: number, newVersion: number) => {console.info(`数据库升级: ${oldVersion} -> ${newVersion}`);try {// 版本1到版本2的升级if (oldVersion < 2) {await rdbStore.executeSql('ALTER TABLE users ADD COLUMN avatar TEXT');}// 版本2到版本3的升级if (oldVersion < 3) {await rdbStore.executeSql('CREATE TABLE IF NOT EXISTS settings (key TEXT PRIMARY KEY, value TEXT)');}// 版本3到版本4的升级if (oldVersion < 4) {await rdbStore.executeSql('ALTER TABLE users ADD COLUMN last_login INTEGER DEFAULT 0');}} catch (error) {console.error(`数据库升级失败: ${(error as BusinessError).message}`);throw error;}
};// 数据库配置
const STORE_CONFIG: relationalStore.StoreConfig = {name: 'app_database.db',securityLevel: relationalStore.SecurityLevel.S2,encrypt: true
};// 初始化数据库
async function initDatabase(context: any): Promise<relationalStore.RdbStore | null> {try {const rdbStore = await relationalStore.getRdbStore(context, STORE_CONFIG);// 设置数据库版本await rdbStore.setVersion(4);// 设置升级回调await rdbStore.setUpgradeCallback(onUpgrade);return rdbStore;} catch (error) {console.error(`数据库初始化失败: ${(error as BusinessError).message}`);return null;}
}
6.2 数据备份与恢复
// utils/backupManager.ts
import fileio from '@ohos.fileio';
import { BusinessError } from '@ohos.base';class BackupManager {private context: any;private backupDir: string;constructor(context: any) {this.context = context;this.backupDir = this.context.filesDir + '/backups';}// 创建备份async createBackup(sourceDir: string, backupName: string): Promise<boolean> {try {const backupPath = `${this.backupDir}/${backupName}`;await fileio.mkdir(backupPath);const files = await fileio.listFile(sourceDir);for (const file of files) {const sourcePath = `${sourceDir}/${file}`;const targetPath = `${backupPath}/${file}`;await this.copyFile(sourcePath, targetPath);}return true;} catch (error) {console.error(`创建备份失败: ${(error as BusinessError).message}`);return false;}}// 恢复备份async restoreBackup(backupName: string, targetDir: string): Promise<boolean> {try {const backupPath = `${this.backupDir}/${backupName}`;if (!await fileio.access(backupPath)) {console.error('备份不存在');return false;}const files = await fileio.listFile(backupPath);for (const file of files) {const sourcePath = `${backupPath}/${file}`;const targetPath = `${targetDir}/${file}`;await this.copyFile(sourcePath, targetPath);}return true;} catch (error) {console.error(`恢复备份失败: ${(error as BusinessError).message}`);return false;}}// 复制文件private async copyFile(sourcePath: string, targetPath: string): Promise<void> {try {const sourceFd = await fileio.open(sourcePath, fileio.OpenMode.READ_ONLY);const targetFd = await fileio.open(targetPath, fileio.OpenMode.CREATE | fileio.OpenMode.WRITE_ONLY);const stat = await fileio.stat(sourceFd);const buffer = new ArrayBuffer(stat.size);await fileio.read(sourceFd, buffer, { offset: 0 });await fileio.write(targetFd, buffer, { offset: 0 });await fileio.close(sourceFd);await fileio.close(targetFd);} catch (error) {console.error(`复制文件失败: ${(error as BusinessError).message}`);throw error;}}// 获取备份列表async listBackups(): Promise<string[]> {try {await fileio.mkdir(this.backupDir);return await fileio.listFile(this.backupDir);} catch (error) {console.error(`获取备份列表失败: ${(error as BusinessError).message}`);return [];}}// 删除备份async deleteBackup(backupName: string): Promise<boolean> {try {const backupPath = `${this.backupDir}/${backupName}`;await fileio.rmdir(backupPath);return true;} catch (error) {console.error(`删除备份失败: ${(error as BusinessError).message}`);return false;}}
}export default BackupManager;
七、实战案例:用户信息管理
7.1 用户信息存储模型
// models/user.ts
export interface User {id?: number;username: string;email: string;phone?: string;avatar?: string;age?: number;created_at?: number;updated_at?: number;
}export interface UserSettings {theme: string;language: string;notifications: boolean;auto_sync: boolean;
}
7.2 用户服务封装
// services/userService.ts
import DatabaseManager from '../utils/databaseManager';
import PreferencesManager from '../utils/preferencesManager';
import SecurePreferencesManager from '../utils/securePreferencesManager';
import { User, UserSettings } from '../models/user';class UserService {private db: DatabaseManager;private prefs: PreferencesManager;private securePrefs: SecurePreferencesManager;constructor(context: any) {this.db = new DatabaseManager(context);this.prefs = PreferencesManager.getInstance(context);this.securePrefs = new SecurePreferencesManager(context);}async init(): Promise<void> {await this.db.init();await this.prefs.init('user_settings');await this.securePrefs.init();}// 用户注册async register(user: User): Promise<number> {return await this.db.insertUser(user.username, user.email, user.age || 0);}// 用户登录async login(username: string, password: string): Promise<boolean> {// 这里应该是密码验证逻辑,实际应用中需要加密验证const user = await this.getUserByUsername(username);if (user) {// 保存登录状态await this.prefs.setString('current_user_id', user.id.toString());await this.prefs.setString('current_username', username);await this.prefs.setBoolean('is_logged_in', true);// 保存登录时间await this.db.updateUserLoginTime(user.id);return true;}return false;}// 获取当前用户async getCurrentUser(): Promise<User | null> {const userId = await this.prefs.getString('current_user_id');if (!userId) return null;return await this.getUserById(parseInt(userId));}// 根据ID查询用户async getUserById(id: number): Promise<User | null> {const users = await this.db.queryUsers();return users.find(user => user.id === id) || null;}// 根据用户名查询用户async getUserByUsername(username: string): Promise<User | null> {const users = await this.db.queryUsers();return users.find(user => user.username === username) || null;}// 更新用户信息async updateUser(user: User): Promise<boolean> {if (!user.id) return false;const result = await this.db.updateUser(user.id,user.username,user.email,user.age || 0);return result > 0;}// 删除用户async deleteUser(id: number): Promise<boolean> {const result = await this.db.deleteUser(id);return result > 0;}// 获取用户设置async getUserSettings(): Promise<UserSettings> {const theme = await this.prefs.getString('theme', 'light');const language = await this.prefs.getString('language', 'zh-CN');const notifications = await this.prefs.getBoolean('notifications', true);const auto_sync = await this.prefs.getBoolean('auto_sync', true);return {theme,language,notifications,auto_sync};}// 保存用户设置async saveUserSettings(settings: UserSettings): Promise<void> {await this.prefs.setString('theme', settings.theme);await this.prefs.setString('language', settings.language);await this.prefs.setBoolean('notifications', settings.notifications);await this.prefs.setBoolean('auto_sync', settings.auto_sync);}// 保存敏感信息(如Token)async saveToken(token: string): Promise<void> {await this.securePrefs.setSecureString('auth_token', token);}// 获取敏感信息async getToken(): Promise<string> {return await this.securePrefs.getSecureString('auth_token', '');}// 退出登录async logout(): Promise<void> {await this.prefs.remove('current_user_id');await this.prefs.remove('current_username');await this.prefs.setBoolean('is_logged_in', false);await this.securePrefs.delete('auth_token');}
}export default UserService;
八、性能优化与最佳实践
8.1 数据库性能优化
// 批量插入数据
async function batchInsertUsers(users: User[]): Promise<void> {if (!this.rdbStore) return;try {await this.rdbStore.beginTransaction();for (const user of users) {const valuesBucket: relationalStore.ValuesBucket = {'name': user.username,'email': user.email,'age': user.age || 0};await this.rdbStore.insert('users', valuesBucket);}await this.rdbStore.commit();} catch (error) {await this.rdbStore.rollBack();console.error(`批量插入失败: ${(error as BusinessError).message}`);throw error;}
}// 使用索引优化查询
async function createIndexes(): Promise<void> {if (!this.rdbStore) return;try {// 为email字段创建索引await this.rdbStore.executeSql('CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)');// 为created_at字段创建索引await this.rdbStore.executeSql('CREATE INDEX IF NOT EXISTS idx_users_created_at ON users(created_at)');console.info('索引创建成功');} catch (error) {console.error(`索引创建失败: ${(error as BusinessError).message}`);}
}// 分页查询
async function queryUsersWithPagination(page: number, pageSize: number): Promise<any[]> {if (!this.rdbStore) return [];const predicates = new relationalStore.RdbPredicates('users');const columns = ['id', 'name', 'email', 'age', 'created_at'];predicates.orderByDesc('created_at').limit(pageSize).offset((page - 1) * pageSize);try {const resultSet = await this.rdbStore.query(predicates, columns);const users: any[] = [];while (resultSet.goToNextRow()) {users.push({id: resultSet.getLong(resultSet.getColumnIndex('id')),name: resultSet.getString(resultSet.getColumnIndex('name')),email: resultSet.getString(resultSet.getColumnIndex('email')),age: resultSet.getLong(resultSet.getColumnIndex('age')),created_at: resultSet.getLong(resultSet.getColumnIndex('created_at'))});}resultSet.close();return users;} catch (error) {console.error(`分页查询失败: ${(error as BusinessError).message}`);return [];}
}
8.2 内存缓存优化
// utils/cacheManager.ts
interface CacheItem<T> {data: T;timestamp: number;ttl: number;
}class CacheManager<T> {private cache: Map<string, CacheItem<T>> = new Map();private maxSize: number = 100; // 最大缓存数量// 设置缓存set(key: string, data: T, ttl: number = 5 * 60 * 1000): void {if (this.cache.size >= this.maxSize) {this.evictOldest();}this.cache.set(key, {data,timestamp: Date.now(),ttl});}// 获取缓存get(key: string): T | null {const item = this.cache.get(key);if (!item) return null;// 检查是否过期if (Date.now() - item.timestamp > item.ttl) {this.cache.delete(key);return null;}return item.data;}// 删除缓存delete(key: string): void {this.cache.delete(key);}// 清理过期缓存cleanup(): void {const now = Date.now();for (const [key, item] of this.cache.entries()) {if (now - item.timestamp > item.ttl) {this.cache.delete(key);}}}// 清理所有缓存clear(): void {this.cache.clear();}// 淘汰最旧的缓存private evictOldest(): void {let oldestKey: string | null = null;let oldestTime = Infinity;for (const [key, item] of this.cache.entries()) {if (item.timestamp < oldestTime) {oldestTime = item.timestamp;oldestKey = key;}}if (oldestKey) {this.cache.delete(oldestKey);}}
}export default CacheManager;
8.3 数据访问层封装
// services/dataService.ts
import DatabaseManager from '../utils/databaseManager';
import CacheManager from '../utils/cacheManager';class DataService {private db: DatabaseManager;private userCache: CacheManager<any>;private settingsCache: CacheManager<any>;constructor(context: any) {this.db = new DatabaseManager(context);this.userCache = new CacheManager();this.settingsCache = new CacheManager();}async init(): Promise<void> {await this.db.init();}// 获取用户信息(带缓存)async getUserById(id: number): Promise<any> {const cacheKey = `user_${id}`;const cachedUser = this.userCache.get(cacheKey);if (cachedUser) {return cachedUser;}const user = await this.db.getUserById(id);if (user) {this.userCache.set(cacheKey, user, 30 * 60 * 1000); // 缓存30分钟}return user;}// 批量获取用户信息async getUsersByIds(ids: number[]): Promise<any[]> {const users: any[] = [];const missingIds: number[] = [];// 先尝试从缓存获取for (const id of ids) {const cacheKey = `user_${id}`;const cachedUser = this.userCache.get(cacheKey);if (cachedUser) {users.push(cachedUser);} else {missingIds.push(id);}}// 批量查询缺失的用户if (missingIds.length > 0) {const dbUsers = await this.db.getUsersByIds(missingIds);for (const user of dbUsers) {const cacheKey = `user_${user.id}`;this.userCache.set(cacheKey, user, 30 * 60 * 1000);users.push(user);}}return users;}// 更新用户信息(同时更新缓存)async updateUser(user: any): Promise<boolean> {const result = await this.db.updateUser(user);if (result) {const cacheKey = `user_${user.id}`;this.userCache.set(cacheKey, user, 30 * 60 * 1000);}return result;}// 清除用户缓存clearUserCache(id?: number): void {if (id) {const cacheKey = `user_${id}`;this.userCache.delete(cacheKey);} else {this.userCache.clear();}}
}export default DataService;
九、总结
通过本篇学习,您已经掌握了:
✅ Preferences存储:轻量级键值对存储,适合用户配置和简单数据
✅ 关系型数据库:复杂结构化数据存储,支持SQL查询和事务操作
✅ 文件存储:大文件读写和管理,支持文本和二进制数据
✅ 数据加密:敏感信息的安全存储,使用AES等加密算法
✅ 数据迁移:数据库版本升级和数据备份恢复
✅ 性能优化:缓存机制、批量操作和索引优化
关键知识点回顾:
- Preferences适合存储少量配置信息,使用简单但功能有限
- 关系型数据库支持复杂查询和事务,适合业务数据存储
- 文件存储适合大文件和二进制数据,需要手动管理
- 敏感数据必须加密存储,使用系统提供的加密库
- 数据库升级需要处理版本迁移,确保数据一致性
- 使用缓存和批量操作可以显著提升性能
最佳实践建议:
- 根据数据量选择合适的存储方案
- 敏感数据必须加密存储
- 数据库操作使用事务保证数据一致性
- 使用缓存减少数据库访问次数
- 定期清理过期数据和缓存
- 实现数据备份和恢复机制
下一篇我们将学习分布式数据管理,掌握如何在多设备间同步数据,实现跨设备无缝体验。