手把手教你在Flutter項目優雅的使用ORM數據庫

Flutter ORM數據庫介紹

Flutter如今開發上最大的槽點可能就是數據庫使用了,Flutter如今只提供了sqflite插件,這代表開發者手動寫sql代碼,建表、建索引、transation、db線程控制等等繁瑣的事情必然接踵而至,這種數據庫使用方式是最低效的了。例如IOS平臺有coredata、realm等等的框架提供便捷的數據庫操做,但來到flutter就又倒退回去裸寫sql,這對大部分團隊都是重大的成本。android

本文將詳細介紹一種在Flutter項目中優雅的使用ORM數據庫的方法,咱們使用的ORM框架是包含在一個Flutter插件flutter_luakit_plugin(如何使用可參考介紹文章)中的其中一個功能,本文只詳細介紹這套ORM框架的使用和實現原理。咱們給出了一個demogit

咱們demo中實現了一個簡單的功能,從一個天氣網站上查詢北京的天氣信息,解析返回的json而後存數據庫,下次啓動優先從數據庫查數據立刻顯示,再發請求向天氣網站更新天氣信息,就這麼簡單的一個功能。雖然功能簡單,可是咱們99%平常的業務邏輯也就是由這些簡單的邏輯組成的了。下面是demo運行的效果圖。github

image

看完運行效果,咱們開始看看ORM數據庫的使用。ORM數據庫的核心代碼都是lua,其中WeatherManager.lua是業務邏輯代碼,其餘的lua文件是ORM數據庫的核心代碼,所有是lua實現的,全部代碼文件加起來也就120k左右,很是輕量。sql

針對上面提到的天氣信息的功能,咱們來設計數據模型,從demo的展現咱們看到天天天氣信息包含幾個信息,城市名、日出日落時間、最高溫度、最低溫度、風向、風力,而後爲了區分是哪一天的數據,咱們給每條信息加上個id的屬性,做爲主鍵。想好咱們就開始定義第一個ORM數據模型,有幾個必要的信息,db名,表名,後面的就是咱們須要的各個字段了,咱們提供IntegerField、RealField、BlobField、TextField、BooleandField。等經常使用的數據類型。weather 就是這個模型的名字,以後咱們weather爲索引使用這個數據模型。定義模型代碼以下。數據庫

weather = {
   __dbname__ = "test.db",
    __tablename__ = "weather",
    id = {"IntegerField",{unique = true, null = false, primary_key = true}},
    wind = {"TextField",{}},
    wind_direction = {"TextField",{}},
    sun_info = {"TextField",{}},
    low = {"IntegerField",{}},
    high = {"IntegerField",{}},
    city =  {"TextField",{}},
 },
複製代碼

定義好模型後,咱們看看如何使用,咱們跟着業務邏輯走,首先網絡請求回來咱們要生成模型對象存到數據庫,分下面幾步json

  • 獲取模型對象
local Table = require('orm.class.table')
local _weatherTable = Table("weather」)
複製代碼
  • 準備數據,創建數據對象
local t = {}
t.wind = flDict[v.fg]
t.wind_direction = fxDict[v.ff]
t.sun_info = v.fi
t.low = tonumber(v.fd)
t.high = tonumber(v.fc)
t.id = i
t.city = city
local weather = _weatherTable(t)
複製代碼
  • 保存數據
weather:save()
複製代碼
  • 讀取數據
_weatherTable.get:all():getPureData()
複製代碼

是否是很簡單,很優雅,什麼建表、拼sql、transation、線程安全等等都不用考慮,傻瓜式地使用,一個業務就幾行代碼搞定。這裏只演示了簡單的存取,更多的select、update、聯表等高級用法可參考db_test demo安全

Flutter ORM數據庫原理詳解

好了,上面已經介紹完如何使用了,若是你們僅僅關心使用下面的能夠不看了,若是你們想了解這套跨平臺的ORM框架的實現原理,下面就會詳細介紹,其實瞭解了實現原理,對你們具體業務使用仍是頗有好處的,雖然我感受你們用的時候極少瞭解原理。網絡

咱們把orm框架分爲三層接入層,cache層,db操做層,三個層分別處於對應的線程,具體能夠參考下圖。接入層能夠在任意線程發起,接入層也是每次數據庫操做的發起點,上面的demo全部操做都是在接入層,cache層,db操做層僅僅是ORM內部劃分,對使用者來說不須要關心cache層和db操做層。咱們把全部的操做分紅兩種,db後續相關的,和db後續無關的。app

image

db後續無關的操做是從接入層不一樣的線程進入到cache層的隊列,全部操做在這個隊列裏先同步完成內存操做,而後便可立刻返回接入層,異步再到db操做層進行db操做。db後續無關的操做包括 save、update、delete。框架

db後續相關的操做依賴db操做層操做的結果,這樣的話就必須等真實的db操做完成了再返回接入層。db後續相關的操做包括select。

要作到這種數據同步,咱們必須先把orm操做接口抽象化,只給幾個經常使用的接口,全部操做都必須經過指定的接口來完成。咱們總結了以下基本操做接口。

一、save

二、select where

三、select PrimaryKey

四、update where

五、update PrimaryKey

六、delete where

七、delete PrimaryKey

這七種操做只要在操做前返回前對內存中的cache作相應的處理,便可保證內存cache始終和db保持一致,這樣之後咱們就能夠優先使用cache層的數據了。這七種操做的實現邏輯,這裏先說明一下,cache裏面的對象都是以主鍵爲key,orm對象爲value的形式存儲在內存中的,這些控制邏輯是寫在cache.lua裏面的。

下面詳細介紹七種基本操做的邏輯。

  • save操做,同步修改內存cache,而後立刻返回接入層,再異步進行db replace into 的操做

image

  • where條件select,這個必須先同步到db線程獲取查詢結果,再同步修改內存裏面的cache值,再返回給接入層

image

  • select PrimaryKey,就是選必定PrimaryKey值的orm對象,這個操做首先看cache裏面是否有primarykey 值的orm對,若是有,直接返回,若是沒有,先同步到db線程獲取查詢結果,再同步修改內存裏面的cache值,再返回給接入層

image

  • update where,先同步到db線程經過where 條件select出須要update的主鍵值,根據主鍵值和須要update的內容,同步更新內存cache,而後異步進行db的update操做

image

  • update PrimaryKey,根據PrimaryKey進行update操做,先同步更新內存cache,而後異步進行db的update操做

image

  • delete where,先同步到db線程經過where 條件select出須要delete的主鍵值,根據主鍵值刪除內存cache,而後異步進行db的delete操做

image

  • delete PrimaryKey,根據PrimaryKey進行delete操做,先同步刪除內存cache,而後異步進行db的delete操做

image

只要保證上面七種基本操做邏輯,便可保證cache中的內容和db最終的內容是一致的,這種儘可能使用cache的特性能夠提高數據庫操做的效率,並且保證同一個db的全部操做都在指定的cache線程和db線程裏面完成,也能夠保證線程安全。

最後,因爲咱們全部的db操做都集中起來了,咱們能夠定時的transation 保存,這樣能夠大幅提高數據庫操做的性能。

結語

目前Flutter領域最大的痛點就是數據庫操做,本文提供了一種優雅使用ORM數據庫的方法,大幅下降了使用數據庫的門檻。但願這篇文章和flutter_luakit_plugin能夠幫到你們更方便的開發Flutter 應用。

相關文章
相關標籤/搜索