HarmonyOS資料管理與應用資料持久化(一)

HarmonyOS開發者社群發表於2023-11-01

一. 資料管理概述

功能介紹

資料管理為開發者提供資料儲存、資料管理能力,比如聯絡人應用資料可以儲存到資料庫中,提供資料庫的安全、可靠等管理機制。

●  資料儲存:提供通用資料持久化能力,根據資料特點,分為使用者首-選項、鍵值型資料庫和關係型資料庫。

●  資料管理:提供高效的資料管理能力,包括許可權管理、資料備份恢復、資料共享框架等。

應用建立的資料庫,都儲存到應用沙盒,當應用解除安裝時,資料庫也會自動刪除。

運作機制

資料管理模組包括使用者首-選項、鍵值型資料管理、關係型資料管理、分散式資料物件和跨應用資料管理。Interface介面層提供標準JS API介面,定義這些部件介面描述,供開發者參考。Frameworks&System service層負責實現部件資料儲存功能,還有一些SQLite和其他子系統的依賴。

圖1 資料管理架構圖

●  使用者首-選項(Preferences):提供了輕量級配置資料的持久化能力,並支援訂閱資料變化的通知能力。不支援分散式同步,常用於儲存應用配置資訊、使用者偏好設定等。

●  鍵值型資料管理(KV-Store):提供了鍵值型資料庫的讀寫、加密、手動備份能力。分散式功能暫不支援。

●  關係型資料管理(RelationalStore):提供了關係型資料庫的增刪改查、加密、手動備份能力。分散式功能暫不支援。

●  分散式資料物件(DataObject):獨立提供物件型結構資料的分散式能力。分散式功能暫不支援。

●  跨應用資料管理(DataShare):提供了向其他應用共享以及管理其資料的方法。僅系統應用可用,非系統應用無需關注,下文不做具體介紹。

二. 應用資料持久化概述

應用資料持久化,是指應用將記憶體中的資料透過檔案或資料庫的形式儲存到裝置上。記憶體中的資料形態通常是任意的資料結構或資料物件,儲存介質上的資料形態可能是文字、資料庫、二進位制檔案等。

HarmonyOS標準系統支援典型的儲存資料形態,包括使用者首-選項、鍵值型資料庫、關係型資料庫。

開發者可以根據如下功能介紹,選擇合適的資料形態以滿足自己應用資料的持久化需要。

●  使用者首-選項(Preferences):通常用於儲存應用的配置資訊。資料透過文字的形式儲存在裝置中,應用使用過程中會將文字中的資料全量載入到記憶體中,所以訪問速度快、效率高,但不適合需要儲存大量資料的場景。

●  鍵值型資料庫(KV-Store):一種非關係型資料庫,其資料以“鍵值”對的形式進行組織、索引和儲存,其中“鍵”作為唯-一識別符號。適合很少資料關係和業務關係的業務資料儲存,同時因其在分散式場景中降低了解決資料庫版本相容問題的複雜度,和資料同步過程中衝突解決的複雜度而被廣泛使用。相比於關係型資料庫,更容易做到跨裝置跨版本相容。

●  關係型資料庫(RelationalStore):一種關係型資料庫,以行和列的形式儲存資料,廣泛用於應用中的關係型資料的處理,包括一系列的增、刪、改、查等介面,開發者也可以執行自己定義的SQL語句來滿足複雜業務場景的需要。

三. 透過使用者首-選項實現資料持久化

場景介紹

使用者首-選項為應用提供Key-Value鍵值型的資料處理能力,支援應用持久化輕量級資料,並對其修改和查詢。當使用者希望有一個全域性唯-一儲存的地方,可以採用使用者首-選項來進行儲存。Preferences會將該資料快取在記憶體中,當使用者讀取的時候,能夠快速從記憶體中獲取資料。Preferences會隨著存放的資料量越多而導致應用佔用的記憶體越大,因此,Preferences不適合存放過多的資料,適用的場景一般為應用儲存使用者的個性化設定(字型大小,是否開啟夜間模式)等。

運作機制

如圖所示,使用者程式透過JS介面呼叫使用者首-選項讀寫對應的資料檔案。開發者可以將使用者首-選項持久化檔案的內容載入到Preferences例項,每個檔案唯-一對應到一個Preferences例項,系統會透過靜態容器將該例項儲存在記憶體中,直到主動從記憶體中移除該例項或者刪除該檔案。

應用首-選項的持久化檔案儲存在應用沙箱內部,可以透過context獲取其路徑。具體可見 獲取應用開發路徑

約束限制

●  Key鍵為string型別,要求非空且長度不超過80個位元組。

●  如果Value值為string型別,可以為空,不為空時長度不超過8192個位元組。

●  記憶體會隨著儲存資料量的增大而增大,所以儲存的資料量應該是輕量級的,建議儲存的資料不超過一萬條,否則會在記憶體方面產生較大的開銷。

介面說明

以下是使用者首-選項持久化功能的相關介面,大部分為非同步介面。非同步介面均有callback和Promise兩種返回形式,下表均以callback形式為例,更多介面及使用方式請見 使用者首-選項

介面名稱

描述

getPreferences(context: Context, name: string, callback: AsyncCallback<Preferences>): void

獲取Preferences例項。

put(key: string, value: ValueType, callback: AsyncCallback<void>): void

將資料寫入Preferences例項,可透過flush將Preferences例項持久化。

has(key: string, callback: AsyncCallback<boolean>): void

檢查Preferences例項是否包含名為給定Key的儲存鍵值對。給定的Key值不能為空。

get(key: string, defValue: ValueType, callback: AsyncCallback<ValueType>): void

獲取鍵對應的值,如果值為null或者非預設值型別,返回預設資料defValue。

delete(key: string, callback: AsyncCallback<void>): void

從Preferences例項中刪除名為給定Key的儲存鍵值對。

flush(callback: AsyncCallback<void>): void

將當前Preferences例項的資料非同步儲存到使用者首-選項持久化檔案中。

on(type: 'change', callback: Callback<{ key : string }>): void

訂閱資料變更,訂閱的Key的值發生變更後,在執行flush方法後,觸發callback回撥。

off(type: 'change', callback?: Callback<{ key : string }>): void

取消訂閱資料變更。

deletePreferences(context: Context, name: string, callback: AsyncCallback<void>): void

從記憶體中移除指定的Preferences例項。若Preferences例項有對應的持久化檔案,則同時刪除其持久化檔案。

開發步驟

1.      匯入使用者首-選項模組。

import dataPreferences from '@ohos.data.preferences';

2.      要透過使用者首-選項實現資料持久化,首先要獲取Preferences例項。讀取指定檔案,將資料載入到Preferences例項,用於資料操作。Stage模型示例:

import UIAbility from '@ohos.app.ability.UIAbility';
class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage) {
    try {
      dataPreferences.getPreferences(this.context, 'mystore', (err, preferences) => {
        if (err) {
          console.error(`Failed to get preferences. Code:${err.code},message:${err.message}`);
          return;
        }
        console.info('Succeeded in getting preferences.');
        // 進行相關資料操作
      })
    } catch (err) {
      console.error(`Failed to get preferences. Code:${err.code},message:${err.message}`);
    }
  }
}

寫入資料。使用put()方法儲存資料到快取的Preferences例項中。在寫入資料後,如有需要,可使用flush()方法將Preferences例項的資料儲存到持久化檔案。

說明

當對應的鍵已經存在時,put()方法會修改其值。如果僅需要在鍵值對不存在時新增鍵值對,而不修改已有鍵值對,需使用has()方法檢查是否存在對應鍵值對;如果不關心是否會修改已有鍵值對,則直接使用put()方法即可。

示例程式碼如下所示:

try {
  preferences.has('startup', function (err, val) {
    if (err) {
      console.error(`Failed to check the key 'startup'. Code:${err.code}, message:${err.message}`);
      return;
    }
    if (val) {
      console.info("The key 'startup' is contained.");
    } else {
      console.info("The key 'startup' does not contain.");
      // 此處以此鍵值對不存在時寫入資料為例
      try {
        preferences.put('startup', 'auto', (err) => {
          if (err) {
            console.error(`Failed to put data. Code:${err.code}, message:${err.message}`);
            return;
          }
          console.info('Succeeded in putting data.');
        })
      } catch (err) {
        console.error(`Failed to put data. Code: ${err.code},message:${err.message}`);
      }
    }
  })
} catch (err) {
  console.error(`Failed to check the key 'startup'. Code:${err.code}, message:${err.message}`);
}

4.      讀取資料。使用get()方法獲取資料,即指定鍵對應的值。如果值為null或者非預設值型別,則返回預設資料。示例程式碼如下所示:

try {
  preferences.get('startup', 'default', (err, val) => {
    if (err) {
      console.error(`Failed to get value of 'startup'. Code:${err.code}, message:${err.message}`);
      return;
    }
    console.info(`Succeeded in getting value of 'startup'. val: ${val}.`);
  })
} catch (err) {
  console.error(`Failed to get value of 'startup'. Code:${err.code}, message:${err.message}`);
}

5.      刪除資料。使用delete()方法刪除指定鍵值對,示例程式碼如下所示:

try {
  preferences.delete('startup', (err) => {
    if (err) {
      console.error(`Failed to delete the key 'startup'. Code:${err.code}, message:${err.message}`);
      return;
    }
    console.info("Succeeded in deleting the key 'startup'.");
  })
} catch (err) {
  console.error(`Failed to delete the key 'startup'. Code:${err.code}, message:${err.message}`);
}

6.      資料持久化。應用存入資料到Preferences例項後,可以使用flush()方法實現資料持久化。示例程式碼如下所示:

try {
  preferences.flush((err) => {
    if (err) {
      console.error(`Failed to flush. Code:${err.code}, message:${err.message}`);
      return;
    }
    console.info('Succeeded in flushing.');
  })
} catch (err) {
  console.error(`Failed to flush. Code:${err.code}, message:${err.message}`);
}

7.      訂閱資料變更。應用訂閱資料變更需要指定observer作為回撥方法。訂閱的Key值發生變更後,當執行flush()方法時,observer被觸發回撥。示例程式碼如下所示

let observer = function (key) {
  console.info('The key' + key + 'changed.');
}
preferences.on('change', observer);
// 資料產生變更,由'auto'變為'manual'
preferences.put('startup', 'manual', (err) => {
  if (err) {
    console.error(`Failed to put the value of 'startup'. Code:${err.code},message:${err.message}`);
    return;
  }
  console.info("Succeeded in putting the value of 'startup'.");
  preferences.flush((err) => {
    if (err) {
      console.error(`Failed to flush. Code:${err.code}, message:${err.message}`);
      return;
    }
    console.info('Succeeded in flushing.');
  })
})

刪除指定檔案。使用deletePreferences()方法從記憶體中移除指定檔案對應的Preferences例項,包括記憶體中的資料。若該Preference存在對應的持久化檔案,則同時刪除該持久化檔案,包括指定檔案及其備份檔案、損壞檔案。

說明

●  呼叫該介面後,應用不允許再使用該Preferences例項進行資料操作,否則會出現資料一致性問題。

●  成功刪除後,資料及檔案將不可恢復。

示例程式碼如下所示:

try {
  dataPreferences.deletePreferences(this.context, 'mystore', (err, val) => {
    if (err) {
      console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`);
      return;
    }
    console.info('Succeeded in deleting preferences.');
  })
} catch (err) {
  console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`);
}


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70009402/viewspace-2992376/,如需轉載,請註明出處,否則將追究法律責任。

相關文章