Harmony学习之分布式数据管理

Harmony学习之分布式数据管理

一、场景引入

小明正在开发一个跨设备待办事项应用,希望用户能在手机、平板、PC等多设备间无缝同步任务数据。当用户在手机上添加任务后,其他设备需要实时显示最新状态,同时要处理多设备同时编辑时的数据冲突问题。HarmonyOS的分布式数据管理能力让这些需求变得简单。

二、核心概念

1. 分布式数据管理架构

HarmonyOS的分布式数据管理采用分层架构设计,主要包括:

  • 服务接口层:提供KV数据模型的数据库创建、访问、订阅等API接口
  • 服务组件层:负责元数据管理、权限管理、加密管理等核心服务
  • 存储组件层:处理数据访问、事务、快照、数据库加密等特性
  • 同步组件层:保持在线设备间数据一致性,实现数据同步
  • 通信适配层:调用底层通信接口完成设备间数据传输

2. 数据同步机制

分布式数据服务采用高效的增量同步策略,只有当数据发生变更时,才会将变更部分通过网络发送给其他设备。系统支持两种同步方式:

  • 自动同步:设备上线或应用更新数据时自动触发
  • 手动同步:应用主动调用sync接口触发同步

3. 一致性模型

HarmonyOS提供多种一致性模型以适应不同场景:

  • 最终一致性:采用冲突解决策略(如最后写入优先),提供更高性能,适用于大多数应用场景
  • 强一致性:基于Paxos衍生算法,确保所有设备数据实时同步,适用于金融、医疗等关键领域
  • 会话一致性:在单个用户会话期间保持强一致性,会话结束后降级为最终一致性

三、关键实现

1. 权限配置

首先需要在module.json5中申请分布式数据同步权限:

// entry/src/main/module.json5
"requestPermissions": [
  {
    "name": "ohos.permission.DISTRIBUTED_DATASYNC",
    "reason": "用于跨设备数据同步",
    "usedScene": {
      "abilities": ["EntryAbility"],
      "when": "inuse"
    }
  }
]

2. 创建分布式数据库管理器

// entry/src/main/ets/utils/DistributedDataManager.ets
import distributedData from '@ohos.data.distributedData';
import common from '@ohos.app.ability.common';

export class DistributedDataManager {
  private kvManager: distributedData.KVManager | null = null;
  private kvStore: distributedData.KVStore | null = null;

  // 初始化数据库管理器
  async initKVManager(context: common.UIAbilityContext): Promise<void> {
    try {
      const kvManagerConfig = {
        bundleName: 'com.example.todoapp',
        userInfo: {
          userId: '0',
          userType: distributedData.UserType.SAME_USER_ID
        }
      };

      this.kvManager = distributedData.createKVManager(kvManagerConfig);
      console.log('分布式数据库管理器创建成功');
    } catch (error) {
      console.error('创建分布式数据库管理器失败:', error);
    }
  }

  // 创建或获取分布式数据库
  async getKVStore(): Promise<distributedData.KVStore | null> {
    if (!this.kvManager) {
      return null;
    }

    try {
      const options = {
        createIfMissing: true,
        encrypt: false,
        autoSync: true, // 开启自动同步
        kvStoreType: distributedData.KVStoreType.SINGLE_VERSION,
        securityLevel: distributedData.SecurityLevel.S1
      };

      this.kvStore = await this.kvManager.getKVStore('todoStore', options);
      console.log('分布式数据库创建成功');
      return this.kvStore;
    } catch (error) {
      console.error('创建分布式数据库失败:', error);
      return null;
    }
  }

  // 订阅数据变化
  async subscribeDataChanges(callback: (data: any) => void): Promise<void> {
    if (!this.kvStore) {
      return;
    }

    const observer = {
      onChange: (notification: distributedData.ChangeNotification) => {
        const insertEntries = notification.getInsertEntries();
        const updateEntries = notification.getUpdateEntries();
        const deleteEntries = notification.getDeleteEntries();
        
        // 处理数据变化
        callback({ insertEntries, updateEntries, deleteEntries });
      }
    };

    await this.kvStore.subscribe(
      distributedData.SubscribeType.SUBSCRIBE_TYPE_ALL,
      observer
    );
  }
}

3. 数据操作接口

// entry/src/main/ets/utils/TodoDataService.ets
import { DistributedDataManager } from './DistributedDataManager';

export interface TodoItem {
  id: string;
  title: string;
  completed: boolean;
  createTime: number;
  updateTime: number;
}

export class TodoDataService {
  private dataManager: DistributedDataManager;
  private kvStore: distributedData.KVStore | null = null;

  constructor(context: common.UIAbilityContext) {
    this.dataManager = new DistributedDataManager();
    this.init(context);
  }

  async init(context: common.UIAbilityContext): Promise<void> {
    await this.dataManager.initKVManager(context);
    this.kvStore = await this.dataManager.getKVStore();
  }

  // 添加待办事项
  async addTodo(todo: TodoItem): Promise<void> {
    if (!this.kvStore) {
      return;
    }

    try {
      const key = `todo_${todo.id}`;
      const value = JSON.stringify(todo);
      await this.kvStore.put(key, value);
      console.log('待办事项添加成功');
    } catch (error) {
      console.error('添加待办事项失败:', error);
    }
  }

  // 更新待办事项
  async updateTodo(todo: TodoItem): Promise<void> {
    if (!this.kvStore) {
      return;
    }

    try {
      const key = `todo_${todo.id}`;
      const value = JSON.stringify({
        ...todo,
        updateTime: Date.now()
      });
      await this.kvStore.put(key, value);
      console.log('待办事项更新成功');
    } catch (error) {
      console.error('更新待办事项失败:', error);
    }
  }

  // 删除待办事项
  async deleteTodo(id: string): Promise<void> {
    if (!this.kvStore) {
      return;
    }

    try {
      const key = `todo_${id}`;
      await this.kvStore.delete(key);
      console.log('待办事项删除成功');
    } catch (error) {
      console.error('删除待办事项失败:', error);
    }
  }

  // 查询所有待办事项
  async getAllTodos(): Promise<TodoItem[]> {
    if (!this.kvStore) {
      return [];
    }

    try {
      const entries = await this.kvStore.getEntries('');
      const todos: TodoItem[] = [];

      for (let i = 0; i < entries.length; i++) {
        const entry = entries[i];
        if (entry.key.startsWith('todo_')) {
          const todo = JSON.parse(entry.value.toString());
          todos.push(todo);
        }
      }

      // 按创建时间排序
      return todos.sort((a, b) => b.createTime - a.createTime);
    } catch (error) {
      console.error('查询待办事项失败:', error);
      return [];
    }
  }

  // 订阅数据变化
  async subscribeTodos(callback: (todos: TodoItem[]) => void): Promise<void> {
    await this.dataManager.subscribeDataChanges(async () => {
      const todos = await this.getAllTodos();
      callback(todos);
    });
  }
}

4. 手动同步数据

// entry/src/main/ets/utils/SyncManager.ets
import distributedData from '@ohos.data.distributedData';
import deviceManager from '@ohos.distributedHardware.deviceManager';

export class SyncManager {
  private kvStore: distributedData.KVStore | null = null;

  constructor(kvStore: distributedData.KVStore) {
    this.kvStore = kvStore;
  }

  // 手动同步数据到所有设备
  async syncAllDevices(): Promise<void> {
    if (!this.kvStore) {
      return;
    }

    try {
      const deviceManager = deviceManager.createDeviceManager('com.example.todoapp');
      const devices = await deviceManager.getTrustedDeviceListSync();
      const deviceIds = devices.map(device => device.deviceId);

      if (deviceIds.length > 0) {
        await this.kvStore.sync(deviceIds, distributedData.SyncMode.PUSH_PULL);
        console.log('数据同步成功');
      }
    } catch (error) {
      console.error('数据同步失败:', error);
    }
  }

  // 同步数据到指定设备
  async syncToDevice(deviceId: string): Promise<void> {
    if (!this.kvStore) {
      return;
    }

    try {
      await this.kvStore.sync([deviceId], distributedData.SyncMode.PUSH_PULL);
      console.log(`数据同步到设备 ${deviceId} 成功`);
    } catch (error) {
      console.error('数据同步失败:', error);
    }
  }
}

四、实战案例:跨设备待办事项应用

1. 主页面实现

// entry/src/main/ets/pages/TodoPage.ets
import { TodoDataService, TodoItem } from '../utils/TodoDataService';
import { SyncManager } from '../utils/SyncManager';
import common from '@ohos.app.ability.common';

@Component
struct TodoPage {
  @State todos: TodoItem[] = [];
  @State newTodoTitle: string = '';
  private todoService: TodoDataService | null = null;
  private syncManager: SyncManager | null = null;

  aboutToAppear() {
    this.initDataService();
  }

  async initDataService() {
    const context = getContext(this) as common.UIAbilityContext;
    this.todoService = new TodoDataService(context);
    
    // 初始化数据
    await this.loadTodos();
    
    // 订阅数据变化
    await this.todoService.subscribeTodos((todos) => {
      this.todos = todos;
    });
  }

  async loadTodos() {
    if (this.todoService) {
      this.todos = await this.todoService.getAllTodos();
    }
  }

  async addTodo() {
    if (!this.newTodoTitle.trim() || !this.todoService) {
      return;
    }

    const todo: TodoItem = {
      id: Date.now().toString(),
      title: this.newTodoTitle,
      completed: false,
      createTime: Date.now(),
      updateTime: Date.now()
    };

    await this.todoService.addTodo(todo);
    this.newTodoTitle = '';
  }

  async toggleTodo(todo: TodoItem) {
    if (!this.todoService) {
      return;
    }

    const updatedTodo = {
      ...todo,
      completed: !todo.completed,
      updateTime: Date.now()
    };

    await this.todoService.updateTodo(updatedTodo);
  }

  async deleteTodo(todo: TodoItem) {
    if (!this.todoService) {
      return;
    }

    await this.todoService.deleteTodo(todo.id);
  }

  async syncData() {
    if (this.todoService && this.syncManager) {
      await this.syncManager.syncAllDevices();
    }
  }

  build() {
    Column() {
      // 标题和同步按钮
      Row() {
        Text('待办事项')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .margin(10)
        
        Button('同步')
          .onClick(() => this.syncData())
          .margin(10)
      }

      // 添加新待办事项
      Row() {
        TextInput({ placeholder: '输入待办事项...', text: this.newTodoTitle })
          .onChange((value) => this.newTodoTitle = value)
          .width('70%')
          .height(40)
          .margin(5)
        
        Button('添加')
          .onClick(() => this.addTodo())
          .width('25%')
          .height(40)
          .margin(5)
      }
      .padding(10)

      // 待办事项列表
      List() {
        ForEach(this.todos, (item: TodoItem) => {
          ListItem() {
            Row() {
              Checkbox()
                .checked(item.completed)
                .onChange(() => this.toggleTodo(item))
                .margin(5)
              
              Text(item.title)
                .fontSize(16)
                .textDecoration(item.completed ? TextDecoration.LineThrough : TextDecoration.None)
                .fontColor(item.completed ? Color.Gray : Color.Black)
                .margin(5)
                .width('70%')
              
              Button('删除')
                .onClick(() => this.deleteTodo(item))
                .width(60)
                .height(30)
                .margin(5)
            }
            .padding(10)
            .width('100%')
          }
        })
      }
      .height('70%')
    }
  }
}

2. 数据冲突处理

// entry/src/main/ets/utils/ConflictResolver.ets
import distributedData from '@ohos.data.distributedData';

export class ConflictResolver {
  // 基于时间戳的冲突解决策略(最后写入优先)
  static timestampResolver(localData: any, remoteData: any): any {
    const localTime = localData?.updateTime || 0;
    const remoteTime = remoteData?.updateTime || 0;
    
    return remoteTime > localTime ? remoteData : localData;
  }

  // 自定义业务逻辑冲突解决
  static customTodoResolver(localData: any, remoteData: any): any {
    // 如果两个设备同时修改了同一个待办事项
    if (localData && remoteData && localData.id === remoteData.id) {
      // 优先保留完成状态
      if (remoteData.completed !== localData.completed) {
        return remoteData.completed ? remoteData : localData;
      }
      
      // 否则按时间戳决定
      return this.timestampResolver(localData, remoteData);
    }
    
    return remoteData;
  }
}

五、最佳实践

1. 性能优化策略

// entry/src/main/ets/utils/PerformanceOptimizer.ets
import distributedData from '@ohos.data.distributedData';

export class PerformanceOptimizer {
  // 批量操作减少网络开销
  static async batchOperations(kvStore: distributedData.KVStore, operations: any[]): Promise<void> {
    try {
      const batch = kvStore.createBatch();
      
      for (const op of operations) {
        if (op.type === 'put') {
          batch.put(op.key, op.value);
        } else if (op.type === 'delete') {
          batch.delete(op.key);
        }
      }
      
      await batch.commit();
    } catch (error) {
      console.error('批量操作失败:', error);
    }
  }

  // 数据分片同步
  static async syncWithCondition(kvStore: distributedData.KVStore, condition: string): Promise<void> {
    try {
      await kvStore.sync([], distributedData.SyncMode.PUSH_PULL, {
        condition: condition,
        conditionArgs: [Date.now() - 86400000] // 只同步24小时内的数据
      });
    } catch (error) {
      console.error('条件同步失败:', error);
    }
  }

  // 智能预加载
  static async preloadData(kvStore: distributedData.KVStore, keys: string[]): Promise<void> {
    try {
      const promises = keys.map(key => kvStore.get(key));
      await Promise.all(promises);
    } catch (error) {
      console.error('数据预加载失败:', error);
    }
  }
}

2. 错误处理与重试机制

// entry/src/main/ets/utils/ErrorHandler.ets
export class ErrorHandler {
  // 带重试的异步操作
  static async withRetry<T>(
    operation: () => Promise<T>,
    maxRetries: number = 3,
    delay: number = 1000
  ): Promise<T> {
    let lastError: Error | null = null;
    
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        return await operation();
      } catch (error) {
        lastError = error;
        console.warn(`操作失败,第${attempt}次重试:`, error);
        
        if (attempt < maxRetries) {
          await new Promise(resolve => setTimeout(resolve, delay * attempt));
        }
      }
    }
    
    throw lastError || new Error('操作失败');
  }

  // 网络状态检测
  static async checkNetworkStatus(): Promise<boolean> {
    try {
      const netManager = network.getDefault();
      const netCapabilities = await netManager.getNetCapabilities();
      return netCapabilities.hasCap(network.NetCap.NET_CAPABILITY_INTERNET);
    } catch (error) {
      console.error('检查网络状态失败:', error);
      return false;
    }
  }
}

3. 数据加密与安全

// entry/src/main/ets/utils/SecurityManager.ets
import distributedData from '@ohos.data.distributedData';
import cryptoFramework from '@ohos.security.crypto';

export class SecurityManager {
  // 创建加密的分布式数据库
  static async createEncryptedKVStore(
    kvManager: distributedData.KVManager,
    storeId: string
  ): Promise<distributedData.KVStore | null> {
    try {
      const options = {
        createIfMissing: true,
        encrypt: true, // 启用加密
        autoSync: true,
        kvStoreType: distributedData.KVStoreType.SINGLE_VERSION,
        securityLevel: distributedData.SecurityLevel.S2 // 金融级安全
      };

      return await kvManager.getKVStore(storeId, options);
    } catch (error) {
      console.error('创建加密数据库失败:', error);
      return null;
    }
  }

  // 敏感数据加密
  static async encryptSensitiveData(data: string): Promise<string> {
    try {
      const keyGenerator = cryptoFramework.createSymKeyGenerator('AES256');
      const cipher = cryptoFramework.createCipher('AES256|GCM|PKCS7');
      
      await cipher.init(
        cryptoFramework.CryptoMode.ENCRYPT_MODE,
        keyGenerator.generateSymKey()
      );
      
      const encrypted = await cipher.doFinal(data);
      return encrypted.data.toString();
    } catch (error) {
      console.error('数据加密失败:', error);
      return data;
    }
  }
}

六、总结与行动建议

通过本篇文章,我们学习了HarmonyOS分布式数据管理的核心概念和完整实现流程。在实际开发中,建议:

  1. 合理选择同步策略:根据业务场景选择自动同步或手动同步,平衡性能和实时性需求
  2. 重视数据冲突处理:根据业务逻辑设计合适的冲突解决策略,确保多设备数据一致性
  3. 优化性能与网络开销:使用批量操作、数据分片、智能预加载等技术减少网络传输
  4. 加强安全防护:对敏感数据启用加密存储,使用TEE环境保护密钥安全
  5. 健壮的错误处理:实现重试机制和网络状态检测,提升应用稳定性

建议读者在掌握基础功能后,进一步学习分布式任务调度、设备虚拟化等进阶内容,打造更强大的跨设备应用体验。

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