9f3a45c6创建于 2025年12月19日历史提交

Database Backup and Restore (C/C++)

When to Use

If an error occurs during the operation or storage, you can restore the database to the previous state and continue the operation.

If a database is tampered with, deleted, or powered off, the database may be unavailable due to data loss, data corruption, or dirty data. In this case, you can use the backup and restore capability to restore the database to the available state.

Currently, only RDB stores (C/C++) supports database backup and restore.

How to Develop

A database backup can be used to quickly restore an RDB store in abnormal state.

  1. Add the following library to CMakeLists.txt.

    libnative_rdb_ndk.z.so
    
  2. Include header files.

    #include <cstring>
    #include "database/rdb/relational_store.h"
    #include "hilog/log.h"
    
  3. Call OH_Rdb_Backup to back up the database.

    OH_Rdb_ConfigV2 *config = OH_Rdb_CreateConfig();
    OH_Rdb_SetDatabaseDir(config, "/data/storage/el2/database");
    OH_Rdb_SetArea(config, RDB_SECURITY_AREA_EL2);
    OH_Rdb_SetStoreName(config, "RdbTest.db");
    OH_Rdb_SetSecurityLevel(config, OH_Rdb_SecurityLevel::S3);
    OH_Rdb_SetBundleName(config, "com.example.nativedemo");
    int errCode = 0;
    OH_Rdb_Store *store = OH_Rdb_CreateOrOpen(config, &errCode);
    // Back up a database.
    int result = OH_Rdb_Backup(store, "/data/storage/el2/database/RdbTest_bak.db");
    OH_Rdb_CloseStore(store);
    store = nullptr;
    OH_Rdb_DestroyConfig(config);
    config = nullptr;
    
  4. Call OH_Rdb_Restore to restore the database.

    OH_Rdb_ConfigV2 *config = OH_Rdb_CreateConfig();
    OH_Rdb_SetDatabaseDir(config, "/data/storage/el2/database");
    OH_Rdb_SetArea(config, RDB_SECURITY_AREA_EL2);
    OH_Rdb_SetStoreName(config, "RdbRestoreTest.db");
    OH_Rdb_SetSecurityLevel(config, OH_Rdb_SecurityLevel::S3);
    OH_Rdb_SetBundleName(config, "com.example.nativedemo");
    int errCode = 0;
    OH_Rdb_Store *store = OH_Rdb_CreateOrOpen(config, &errCode);
    // Restore the database.
    int result2 =
        OH_Rdb_Restore(store, "/data/storage/el2/database/RdbTest_bak.db");
    OH_Rdb_CloseStore(store);
    store = nullptr;
    OH_Rdb_DestroyConfig(config);
    config = nullptr;
    
  5. Call OH_Rdb_RegisterCorruptedHandler to register a handler for processing database exceptions.

    Since API version 22, you can call OH_Rdb_RegisterCorruptedHandler to register a handler for processing database exceptions.

    // Callback function for processing database exceptions.
    // context is the pointer passed when OH_Rdb_RegisterCorruptedHandler is called. The lifecycle is managed by the service.
    // config is a temporary variable copied when OH_Rdb_RegisterCorruptedHandler is called. It cannot be used outside the callback function.
    // store is the handle of the database where an exception occurs. If the database cannot be opened, the pointer is null. The pointer is generated by the system and is released immediately after the callback function ends. It cannot be used outside the callback function.
    void CorruptedHandler(void *context, OH_Rdb_ConfigV2 *config, OH_Rdb_Store *store)
    {
        const char* restorePath = "/data/storage/el2/database/RdbTest_bak.db";
        // If store is null, the database file does not exist or cannot be opened.
        if (store == nullptr) {
            OH_Rdb_DeleteStoreV2(config);
            // If there is a standby database, recreate the database and then call the restore API.
            return;
        }
        // Use the standby database to restore the database through the store handle.
        int errCode = OH_Rdb_Restore(store, restorePath);
        // The restore operation will fail if other APIs are occupying the write connection. Call this API after other calls are complete.
        if (errCode != 0) {
            OH_LOG_ERROR(LOG_APP, "restore failed! errCode is: %{public}d", errCode);
            // Wait until other threads' calls are complete and retry. Do not retry for too many times or wait for too long to avoid occupying too many system resources.
            errCode = OH_Rdb_Restore(store, restorePath);
            // Alternatively, mark the database exception and restore the database when the process is restarted or the service is idle.
        }
    }
    OH_Rdb_ConfigV2* config3 = OH_Rdb_CreateConfig();
    OH_Rdb_SetDatabaseDir(config3, "/data/storage/el2/database");
    OH_Rdb_SetArea(config3, RDB_SECURITY_AREA_EL2);
    OH_Rdb_SetStoreName(config3, "RdbRestoreTest.db");
    OH_Rdb_SetSecurityLevel(config3, OH_Rdb_SecurityLevel::S3);
    OH_Rdb_SetBundleName(config3, "com.example.nativedemo");
    int errCode3 = 0;
    OH_Rdb_Store *store3 = OH_Rdb_CreateOrOpen(config3, &errCode3);
    
    // Back up a database.
    int result = OH_Rdb_Backup(store3, "/data/storage/el2/database/RdbTest_bak.db");
    
    void *context = nullptr;
    Rdb_CorruptedHandler handler = CorruptedHandler;
    // Register a handler for processing database exceptions.
    OH_Rdb_RegisterCorruptedHandler(config3, context, handler);
    
  6. Call OH_Rdb_UnregisterCorruptedHandler to unregister the database exception handler.

    Since API version 22, you can call OH_Rdb_UnregisterCorruptedHandler to unregister a database exception handler.

    OH_Rdb_ConfigV2* config4 = OH_Rdb_CreateConfig();
    OH_Rdb_SetDatabaseDir(config4, "/data/storage/el2/database");
    OH_Rdb_SetArea(config4, RDB_SECURITY_AREA_EL2);
    OH_Rdb_SetStoreName(config4, "RdbRestoreTest.db");
    OH_Rdb_SetSecurityLevel(config4, OH_Rdb_SecurityLevel::S3);
    OH_Rdb_SetBundleName(config4, "com.example.nativedemo");
    int errCode4 = 0;
    OH_Rdb_Store *store4 = OH_Rdb_CreateOrOpen(config4, &errCode4);
    
    void *context = nullptr;
    Rdb_CorruptedHandler handler = CorruptedHandler;
    // Unregister the database exception handler. The handler and context must be the same as those during subscription. Otherwise, the operation fails.
    OH_Rdb_UnregisterCorruptedHandler(config4, context, handler);