HarmonyOS 5开发从入门到精通(八):本地数据存储与持久化

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_age
    FROM 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适合存储少量配置信息,使用简单但功能有限
  • 关系型数据库支持复杂查询和事务,适合业务数据存储
  • 文件存储适合大文件和二进制数据,需要手动管理
  • 敏感数据必须加密存储,使用系统提供的加密库
  • 数据库升级需要处理版本迁移,确保数据一致性
  • 使用缓存和批量操作可以显著提升性能

最佳实践建议

  1. 根据数据量选择合适的存储方案
  2. 敏感数据必须加密存储
  3. 数据库操作使用事务保证数据一致性
  4. 使用缓存减少数据库访问次数
  5. 定期清理过期数据和缓存
  6. 实现数据备份和恢复机制

下一篇我们将学习分布式数据管理,掌握如何在多设备间同步数据,实现跨设备无缝体验。

posted @ 2025-12-23 20:02  奇崽  阅读(0)  评论(0)    收藏  举报