鸿蒙5离线数据处理:AGC云数据库的同步策略详解

一、AGC云数据库与离线同步概述

  1. AGC云数据库核心特性
    AGC(AppGallery Connect)云数据库提供:

​​实时同步​​:设备间数据自动同步
​​离线优先​​:无网络时本地操作,恢复连接后自动同步
​​多端一致​​:跨设备数据一致性保障
​​安全规则​​:细粒度的数据访问控制
2. 离线同步工作原理
graph LR
A[本地操作] --> B[本地数据库]
B --> C{网络可用?}
C -->|是| D[同步到云端]
C -->|否| E[队列缓存]
D --> F[其他设备同步]

二、环境配置与初始化

  1. 添加依赖
    在entry/build.gradle中配置:

dependencies {
// AGC核心
implementation 'com.huawei.agconnect:agconnect-core-harmony:1.6.5.300'
// 云数据库
implementation 'com.huawei.agconnect:agconnect-clouddb-harmony:1.6.5.300'
// 认证服务(可选)
implementation 'com.huawei.agconnect:agconnect-auth-harmony:1.6.5.300'
}
2. 初始化云数据库
创建CloudDBManager.ets:

import clouddb from '@hw-agconnect/clouddb';
import agconnect from '@hw-agconnect/core';

export class CloudDBManager {
private static instance: CloudDBManager | null = null;
private cloudDB: clouddb.CloudDBZone | null = null;

private constructor() {}

public static getInstance(): CloudDBManager {
    if (!CloudDBManager.instance) {
        CloudDBManager.instance = new CloudDBManager();
    }
    return CloudDBManager.instance;
}

// 初始化云数据库
async initialize(): Promise<void> {
    try {
        // 1. 初始化AGC
        agconnect.instance().init();
        
        // 2. 创建CloudDB实例
        const cloudDBZoneConfig = new clouddb.CloudDBZoneConfig(
            'QuickStartDemo', // 数据库名称
            clouddb.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE, // 同步策略
            clouddb.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC // 访问权限
        );
        
        // 3. 打开数据库
        this.cloudDB = await clouddb.CloudDBZone.open(cloudDBZoneConfig);
        
        console.log('CloudDB初始化成功');
    } catch (error) {
        console.error('CloudDB初始化失败:', error);
        throw error;
    }
}

// 获取数据库实例
getCloudDB(): clouddb.CloudDBZone {
    if (!this.cloudDB) {
        throw new Error('CloudDB未初始化');
    }
    return this.cloudDB;
}

}
三、数据模型定义与同步策略

  1. 定义对象类型
    创建model/BookInfo.ets:

@Class
export class BookInfo {
@Field()
id: string = '';

@Field({ isIndex: true })
bookName: string = '';

@Field()
author: string = '';

@Field()
price: number = 0;

@Field({ isLocal: true }) // 标记为本地字段,不同步
lastReadTime: number = 0;

@Field({ isNeedEncrypt: true }) // 加密字段
secretNote: string = '';

@Field()
@PrimaryKey()
get primaryKey(): string {
    return this.id;
}

}
2. 注册对象类型
在CloudDBManager中添加:

private objectTypes = [BookInfo];

async initialize(): Promise {
// ...原有代码...

// 注册对象类型
await clouddb.CloudDBZone.registerObjectClass(
    this.objectTypes.map(type => type.name)
);

console.log('对象类型注册成功');

}
四、离线数据操作实现

  1. 新增数据(离线优先)
    // 在CloudDBManager中添加
    async addBook(book: BookInfo): Promise {
    try {
    const db = this.getCloudDB();
    book.id = this.generateId(); // 生成唯一ID

     // 设置最后阅读时间(本地字段)
     book.lastReadTime = new Date().getTime();
     
     // 执行插入
     await db.executeUpsert([book]);
     console.log('书籍添加成功:', book.id);
    

    } catch (error) {
    console.error('添加书籍失败:', error);
    throw error;
    }
    }

private generateId(): string {
return 'book_' + Math.random().toString(36).substr(2, 9);
}
2. 查询数据(本地缓存优先)
// 在CloudDBManager中添加
async queryBooks(
conditions?: clouddb.CloudDBZoneQuery,
policy: clouddb.CloudDBZoneQueryPolicy = clouddb.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY
): Promise<BookInfo[]> {
try {
const db = this.getCloudDB();

    // 默认查询所有书籍
    const query = conditions || clouddb.CloudDBZoneQuery.where(BookInfo);
    
    // 执行查询
    const snapshot = await db.executeQuery(
        query,
        policy // 查询策略
    );
    
    // 获取结果
    const books: BookInfo[] = [];
    while (snapshot.hasNext()) {
        books.push(snapshot.next());
    }
    snapshot.release();
    
    return books;
} catch (error) {
    console.error('查询书籍失败:', error);
    throw error;
}

}
3. 更新与删除操作
// 在CloudDBManager中添加
async updateBook(book: BookInfo): Promise {
try {
const db = this.getCloudDB();
book.lastReadTime = new Date().getTime();
await db.executeUpsert([book]);
console.log('书籍更新成功:', book.id);
} catch (error) {
console.error('更新书籍失败:', error);
throw error;
}
}

async deleteBook(bookId: string): Promise {
try {
const db = this.getCloudDB();
const book = new BookInfo();
book.id = bookId;
await db.executeDelete([book]);
console.log('书籍删除成功:', bookId);
} catch (error) {
console.error('删除书籍失败:', error);
throw error;
}
}
五、同步策略与冲突解决

  1. 同步策略配置
    策略类型 说明 适用场景
    CLOUDDBZONE_LOCAL_ONLY 仅本地操作 临时数据
    CLOUDDBZONE_CLOUD_CACHE 本地优先,自动同步 大多数场景
    CLOUDDBZONE_CLOUD_ONLY 仅云端操作 强一致性要求

  2. 冲突解决策略
    // 在CloudDBManager中添加
    async syncWithConflictResolution(): Promise {
    try {
    const db = this.getCloudDB();

     // 1. 获取未同步操作
     const pendingWrites = await db.getPendingWrites();
     
     // 2. 处理冲突
     for (const write of pendingWrites) {
         try {
             // 尝试同步
             await db.executeUpsert([write.object]);
             
             // 同步成功后删除本地记录
             await db.removePendingWrite(write);
         } catch (syncError) {
             console.warn(`同步冲突: ${write.object.id}`, syncError);
             
             // 冲突处理方案1:使用服务器版本
             const serverVersion = await this.queryBookFromServer(write.object.id);
             await db.executeUpsert([serverVersion]);
             
             // 冲突处理方案2:合并字段(自定义逻辑)
             // this.mergeConflict(write.object, serverVersion);
             
             // 标记为已处理
             await db.removePendingWrite(write);
         }
     }
    

    } catch (error) {
    console.error('同步处理失败:', error);
    }
    }

private async queryBookFromServer(bookId: string): Promise {
const db = this.getCloudDB();
const query = clouddb.CloudDBZoneQuery.where(BookInfo)
.equalTo('id', bookId);

const snapshot = await db.executeQuery(
    query,
    clouddb.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY
);

if (snapshot.hasNext()) {
    return snapshot.next();
}
throw new Error('未找到书籍');

}
六、网络状态监听与自动同步

  1. 网络状态监听
    创建NetworkManager.ets:

import connection from '@ohos.net.connection';

export class NetworkManager {
private static instance: NetworkManager | null = null;
private netHandle: connection.NetHandle;

private constructor() {
    this.netHandle = connection.getDefaultNet();
}

public static getInstance(): NetworkManager {
    if (!NetworkManager.instance) {
        NetworkManager.instance = new NetworkManager();
    }
    return NetworkManager.instance;
}

// 检查网络状态
isConnected(): boolean {
    try {
        return this.netHandle.hasInternet();
    } catch (error) {
        console.error('检查网络状态失败:', error);
        return false;
    }
}

// 监听网络变化
onNetworkChange(callback: (connected: boolean) => void): void {
    connection.on('netAvailable', (data: { netHandle: connection.NetHandle }) => {
        callback(data.netHandle.hasInternet());
    });
    
    connection.on('netUnavailable', () => {
        callback(false);
    });
}

}
2. 自动同步策略实现
在CloudDBManager中添加:

private syncInterval: number = 0;
private isSyncing: boolean = false;

// 启动自动同步
startAutoSync(interval: number = 30000): void {
this.syncInterval = interval;
this.setupNetworkListener();
this.runSyncLoop();
}

private setupNetworkListener(): void {
NetworkManager.getInstance().onNetworkChange(async (connected) => {
if (connected) {
console.log('网络恢复,触发同步');
await this.syncData();
}
});
}

private async runSyncLoop(): Promise {
while (this.syncInterval > 0) {
await new Promise(resolve => setTimeout(resolve, this.syncInterval));

    if (NetworkManager.getInstance().isConnected() && !this.isSyncing) {
        await this.syncData();
    }
}

}

private async syncData(): Promise {
if (this.isSyncing) return;

this.isSyncing = true;
try {
    console.log('开始数据同步...');
    
    // 1. 同步本地更改到云端
    await this.syncWithConflictResolution();
    
    // 2. 从云端获取最新数据
    await this.pullLatestData();
    
    console.log('数据同步完成');
} catch (error) {
    console.error('同步过程中出错:', error);
} finally {
    this.isSyncing = false;
}

}

private async pullLatestData(): Promise {
try {
// 示例:同步所有书籍数据
const db = this.getCloudDB();
const query = clouddb.CloudDBZoneQuery.where(BookInfo);

    // 使用POLICY_QUERY_FROM_CLOUD_ONLY强制从云端获取
    await db.executeQuery(
        query,
        clouddb.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY
    );
} catch (error) {
    console.error('拉取最新数据失败:', error);
    throw error;
}

}
七、实战案例:离线优先的阅读应用

  1. 页面实现:图书列表
    @Entry
    @Component
    struct BookListPage {
    @State books: BookInfo[] = [];
    @State loading: boolean = true;
    @State networkStatus: string = '检查中...';

    private cloudDB = CloudDBManager.getInstance();

    onPageShow() {
    this.loadBooks();
    this.checkNetwork();
    }

    async loadBooks() {
    this.loading = true;
    try {
    // 优先从本地缓存查询
    this.books = await this.cloudDB.queryBooks(
    undefined,
    clouddb.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_LOCAL_ONLY
    );

         // 网络可用时同步最新数据
         if (NetworkManager.getInstance().isConnected()) {
             const cloudBooks = await this.cloudDB.queryBooks();
             this.books = cloudBooks;
         }
     } catch (error) {
         console.error('加载书籍失败:', error);
     } finally {
         this.loading = false;
     }
    

    }

    async checkNetwork() {
    const isConnected = NetworkManager.getInstance().isConnected();
    this.networkStatus = isConnected ? '已连接' : '离线模式';
    }

    build() {
    Column() {
    Text('我的书库')
    .fontSize(24)
    .margin(10);

         Text(`状态: ${this.networkStatus}`)
             .fontColor(this.networkStatus === '离线模式' ? Color.Red : Color.Green);
         
         if (this.loading) {
             LoadingProgress()
                 .margin(20);
         } else {
             List({ space: 10 }) {
                 ForEach(this.books, (book: BookInfo) => {
                     ListItem() {
                         BookItem({ book: book })
                     }
                 })
             }
             .width('100%')
             .height('80%')
         }
     }
     .width('100%')
     .height('100%')
    

    }
    }

@Component
struct BookItem {
@Prop book: BookInfo;

build() {
    Row() {
        Column() {
            Text(this.book.bookName)
                .fontSize(18);
            Text(this.book.author)
                .fontSize(14)
                .fontColor(Color.Gray);
        }
        .margin(10)
        
        Text(`¥${this.book.price.toFixed(2)}`)
            .fontSize(16)
            .fontColor(Color.Blue)
            .margin({ right: 15 })
    }
    .width('100%')
    .justifyContent(FlexAlign.SpaceBetween)
}

}
2. 页面实现:添加/编辑图书
@Entry
@Component
struct BookEditPage {
@State book: BookInfo = new BookInfo();
@State isNew: boolean = true;
@State saving: boolean = false;

private cloudDB = CloudDBManager.getInstance();

onPageShow() {
    const params = router.getParams();
    if (params && params.book) {
        this.book = params.book;
        this.isNew = false;
    }
}

async saveBook() {
    this.saving = true;
    try {
        if (this.isNew) {
            await this.cloudDB.addBook(this.book);
        } else {
            await this.cloudDB.updateBook(this.book);
        }
        
        // 返回并刷新列表
        router.back();
    } catch (error) {
        console.error('保存失败:', error);
    } finally {
        this.saving = false;
    }
}

build() {
    Column({ space: 15 }) {
        Text(this.isNew ? '添加新书' : '编辑书籍')
            .fontSize(22)
            .margin(10);
        
        TextInput({ text: this.book.bookName })
            .placeholder('书名')
            .onChange((value: string) => {
                this.book.bookName = value;
            })
            .width('90%');
        
        TextInput({ text: this.book.author })
            .placeholder('作者')
            .onChange((value: string) => {
                this.book.author = value;
            })
            .width('90%');
        
        TextInput({ text: this.book.price.toString() })
            .placeholder('价格')
            .type(InputType.Number)
            .onChange((value: string) => {
                this.book.price = parseFloat(value) || 0;
            })
            .width('90%');
        
        Button(this.saving ? '保存中...' : '保存')
            .width(200)
            .height(50)
            .backgroundColor(Color.Blue)
            .enabled(!this.saving)
            .onClick(() => {
                this.saveBook();
            })
    }
    .width('100%')
    .height('100%')
    .padding(20)
}

}
八、性能优化与调试技巧

  1. 批量操作优化
    // 在CloudDBManager中添加
    async batchAddBooks(books: BookInfo[]): Promise {
    try {
    const db = this.getCloudDB();

     // 分配ID
     books.forEach(book => {
         book.id = this.generateId();
         book.lastReadTime = new Date().getTime();
     });
     
     // 分批处理(每批50条)
     const batchSize = 50;
     for (let i = 0; i < books.length; i += batchSize) {
         const batch = books.slice(i, i + batchSize);
         await db.executeUpsert(batch);
         console.log(`已批量添加 ${batch.length} 本书籍`);
     }
    

    } catch (error) {
    console.error('批量添加失败:', error);
    throw error;
    }
    }

  2. 数据同步状态监控
    // 在CloudDBManager中添加
    async getSyncStatus(): Promise<{
    pendingWrites: number,
    lastSyncTime: number,
    syncError?: string
    }> {
    try {
    const db = this.getCloudDB();
    const pendingWrites = await db.getPendingWrites();

     return {
         pendingWrites: pendingWrites.length,
         lastSyncTime: Date.now() // 实际应用中应记录真实时间
     };
    

    } catch (error) {
    return {
    pendingWrites: 0,
    lastSyncTime: 0,
    syncError: error.message
    };
    }
    }

  3. 调试日志配置
    // 在应用启动时设置
    clouddb.setLogLevel(clouddb.CloudDBLogLevel.DEBUG);

// 监听数据库事件
clouddb.on('event', (event) => {
console.log('CloudDB事件:', event.type, event.data);

if (event.type === 'syncComplete') {
    console.log('数据同步完成');
} else if (event.type === 'syncError') {
    console.error('同步错误:', event.data);
}

});
总结
通过本文的学习,你已经掌握了在HarmonyOS 5应用中实现AGC云数据库离线同步的核心技术:

​​环境配置​​:正确初始化云数据库服务
​​数据建模​​:定义支持离线同步的数据结构
​​CRUD操作​​:实现离线优先的数据访问
​​同步策略​​:配置冲突解决和网络状态感知
​​实战案例​​:构建完整的离线优先应用
AGC云数据库的离线同步能力为HarmonyOS应用提供了:

​​无缝用户体验​​:网络中断不影响核心功能
​​数据一致性​​:自动解决多设备同步冲突
​​开发效率​​:简化本地和云端数据管理
在实际项目中,你还可以进一步探索:

更复杂的冲突解决策略
数据变更订阅通知
与AGC认证服务的深度集成
大数据量下的性能调优

posted @ 2025-06-28 22:49  暗雨YA  阅读(49)  评论(0)    收藏  举报