yii.
← Writing
Flutter 技術 · · 5 min read

輕鬆了解 Isar NoSQL DB,用它來實作 Flutter 資料庫吧!

這篇寫於 2022 年。工具和 API 變化很快,部分步驟可能已經不適用。

很快能上手的資料庫套件


Isar DatabaseSuper Fast Cross-Platform Database for Flutter Let’s Get Started! Minimal setup, Easy to use, no config, no…isar.dev

  • 作者為了改善 Hive 而開發 Isar,也推薦未來使用 Isar
  • 使用 NoSQL,容量小且速度快
  • 擁有 Isar Inspector 檢查工具,類似 Flutter Devtool。提供視覺化呈現,輕鬆了解資料庫狀況,即時更新
  • 存取操作預設都是非同步,避免堵塞 UI Thread。另外也有提供同步API,除非必要否則應盡力避免使用,不過因速度快同步也影響不大
  • 可搭配 Isolate 使用,如果有另起 Isolate 進行資料處理,則可以進行同步操作,速度很快
  • 透過 Generator 自動生成存取、操作所需的程式碼,節省重複工作
  • 支援在 Mobile 和 Web 上運作,但個別有些許限制

Installation#

flutter pub add isar isar_flutter_libs
flutter pub add -d isar_generator build_runner
pubspec.yaml
pubspec.yaml

標註#

@collection#

代表集合,class上新增標記

@Collection()#

代表集合,可以透過參數進行細部設定

  • inheritance → 是否儲存父類的屬性以及 mixins,預設 true
  • accessor → 自定義集合的入口。假如 class 為 User,通常是 users 為存取入口
  • ignore → 忽略,不要儲存指定欄位

@Name#

指定表和欄位名稱。建議集合跟屬性都要使用,為臨時改名做準備

@ignore#

不需要屬性在資料表建立欄位

@Enumerated#

枚舉,提供四種儲存類型

  • ordinal,byte,無法空值,較快但無法改變 enum 順序,否則會回傳錯誤資料
  • ordinal32,short,無法空值,無法改變 enum 順序,否則會回傳錯誤資料
  • name,String,預設方式
  • value,String,custom String

支援的欄位型別#

一般資料欄位都是 nullable

  • ID → 可以給予 Isar.autoIncrement,不為空值的自動遞增。給予null 也是自動遞增
  • bool
  • int
  • double
  • DateTime
  • String
  • List<bool>
  • List<int>
  • List<double>
  • List<DateTime>
  • List<String>

創建集合、資料表#

執行代碼生成,建立樣板代碼#

flutter pub run build_runner build

建立 Isar 實體,存取指定集合#

final isar = await Isar.open(
  [UserSchema],
  inspector: true,
);
  • 設置要存取的 Collection,這邊添加自動生成的 Schema 類
  • inspector 檢查工具,類似 Flutter DevTools,在 profile 和 release 模式無法使用
  • 單一實體,每次 open() 都會取得相同實體,對於在 Isolate 操作很有用

存取集合#

有提供兩種方式

//1.
isar.users

//2.
isar.collection<User>()

🐦 取得全部資料#

isar.users.where().findAll()

🐦 透過Id取得指定資料#

isar.users.get(1);

🐦 取得集合大小#

isar.users.getSize();

🐦 過濾資料#

Isar 提供很多常用的 API 函式,方便使用,不需要自己撰寫。例如:查詢名字裡有 Chen 的使用者

isar.users.filter().nameContains('Chen').findAll();

🐦 新增資料#

只要有修改資料庫的操作都需要在 transaction 裡處理,使用 writeTxn()

// Single
await isar.writeTxn(() => isar.users.put(user));

// Multiple
await isar.writeTxn(() => isar.users.putAll(users));

🐦 更新資料#

user.name = 'Jay'
await isar.writeTxn(() => isar.users.put(user));

🐦 刪除資料#

isar.writeTxn(() => isar.users.delete(1));

索引(Indexes)#

  • 針對常用來查詢、過濾的欄位可以思考是否設置索引,Isar 會為索引欄位生成特定 API,使用上可以達到更省事更快速的性能
  • 搭配 where() 查詢
  • .anyXXX() 生成函式,僅使用索引進行排序

可設置參數#

  • unique → 唯一索引,此欄位無法出現相同內容
  • replace → 可替換索引,新 Object 可覆蓋
  • caseSensitive → 索引區分大小寫,預設為 true

索引種類#

  • IndexType.value → 值索引,預設索引,最靈活但佔空間
  • IndexType.hash → 哈希索引,空間小但有些 API 不支援,例如:startsWith()
  • IndexType.hashElements → 哈希元素索引,進行散列,適用於List<String>

索引查詢#

// 使用 age 索引進行排序,只撈兩筆
isar.users.where().anyAge().limit(2).findAll();

複合索引(Composite indexes)#

  • 也稱為 multiple-column indexes
  • Isar 允許最多創建三個屬性的複合索引
  • 適合想創建根據多個屬性排序的高效查詢

多項索引(Multi-entry indexes)#

列表中的每個元素都是索引

Isar.splitWords() 補充,可以完整切分字串,忽略空白以及標點符號

全文搜尋 Example,透過索引搜尋的效能很高,速度快

isar.users.where().descriptionWordsElementEqualTo('Chen').findAll();

Watchers 觀察者#

監聽指定集合和物件的更新,即時作出反應,執行對應操作

watchObject()#

  • 監聽物件
  • id → 集合索引
  • fireImmediately → 設為 true,在一開始就將當前值新增到 Stream。預設為 false
Stream<User?> userUpdatedStream = isar.users.watchObject(1);
userUpdatedStream.listen((user) {
  print('index 1 of user updated - $user');
});

watch()#

  • 監聽集合
  • 只要集合有更新就通知,並取得最新集合
Stream<List<User>> usersStream = isar.users.where().watch();
usersStream.listen((users) {
 print('User collection updated - $users');
});

watchObjectLazy()#

  • 懶監聽物件
  • 不需要了解新內容,只需知道資料有更新
Stream<void> userUpdatedStream = isar.users.watchObjectLazy(2);
userUpdatedStream.listen(() {
  print('index 2 of user updated.');
});

watch()#

  • 懶監聽集合
Stream<void> usersUpdatedStream = isar.users.watchLazy();
usersUpdatedStream.listen((voidEvent) {
 print('User collection updated.');
});

watch query#

  • 監聽查詢
  • 使用 build() 建立 Query 物件,透過 Query 進行 watch() 監聽

注意:非必要請使用 lazy 操作,因為資料更新後的重新查詢效率很低

isar.users.filter().nameContains('Chen').build()

Isolate 多隔離操作#

  • 如果需要存取大量資料可以考慮使用新的 Isolate 去處理,避免阻塞 Main isolate(UI thread)
  • 可以在不同隔離存取相同 DB 實體。如果是新的 Isolate 就需要先執行 open() 取得實體,因為每個隔離的內存是獨立的
  • 簡單快速的方式是使用 compute(),更建議透過 Isolate pool 處理

Isar Inspector 工具#

App 運行後再 console 會看到本地網址,點擊後即可查看即時的資料庫狀態,擁有視覺化效果

Source Code#

GitHub - chyiiiiiiiiiiii/isar_example: Simple and easy-understand example for Isar databaseYou can’t perform that action at this time. You signed in with another tab or window. You signed out in another tab or…github.com


其他文章#

關於我#

贊助#

謝謝你花費時間看完,非常感謝!

如果覺得文章不錯的話可以贊助,讓我有更多動力和熱情分享學習紀錄和生活!請我喝一杯咖啡吧~

https://www.buymeacoffee.com/yiichenhi

最後#

希望有幫助到你/妳,歡迎追蹤我,方便瀏覽最新的文章~

本文原刊登於 Medium。