資料庫隨筆
背景
目前軟體開發行業中,無論是移動端開發還是後端開發,基本上都會碰到資料庫的開發,這裡就談談筆者對於資料庫的感想
衝突
在移動端亦或是後端開發中,很多時候,我們會感覺到無論是 ORM 還是其他方案,都會存在著一些缺點,其實這來源於資料庫本身和開發語言本身的衝突,現代化的語言基本上都是物件導向開發,物件導向是從軟體工程基本原則(如耦合、聚合和封裝)的基礎上發展起來的,而關聯式資料庫則是從數學理論發展而來的,兩套理論存在顯著的區別。
資料庫最初的時候就是起源於檔案,一個程式開啟一個檔案,然後將一些資料存入檔案中,最後關閉檔案,從這個需求開發,發展出了資料庫。目前主流關係型資料庫主要有兩種,一種是基於網路傳輸的資料庫,一種則是嵌入式資料庫,這兩種資料庫區別就在於是否存在完善的許可權管理和是否服務端程式碼嵌入到了程式中。
無論是哪種關係型資料庫,開發者都是通過 SQL 語言和其打交道,主流的 ORM 技術實際上只是由資料庫中查詢資料,按條讀取結果集中每一個欄位,然後裝配成物件,或者需要把物件的每一個屬性拆出來,拼湊成SQL字串,再提交資料庫。
ORM 技術
廣義上,ORM指的是物件導向的物件模型和關係型資料庫的資料結構之間的相互轉換。 狹義上,ORM可以被認為是,基於關係型資料庫的資料儲存,實現一個虛擬的物件導向的資料訪問介面。這裡指的 ORM 是指 Hibernate 這樣的框架,至於 ORM 框架的好處就不說了,ORM 一般情況下,一個持久化類和一個表對應,類的每個例項對應表中的一條記錄,類的每個屬性對應表的每個欄位。 但是,這本身 SQL 語言是存在衝突的,我們先來拆分一下要求
- 資料庫需要做 Migration(比如建表,增加欄位,刪除欄位,描述預設值,增加索引,增加約束等)
- 表和表通過關係產生聯絡
- SQL 語句可以讓你只選擇自己需要的列
- SQL 語句引數和結果不保證型別安全
- 結果可能是虛的,比如儲存過程和檢視
物件導向和上面的行為實際上是格格不入的,比如將表抽象為一個類,每個類的例項是一行資料,看起來確實很完美,但是其實存在一個隱藏的缺陷。
- 首先,主要的資料庫操作,基本都是 CRUD 組成,一般來說,增加、刪除、更新語法都是差不多的,很容易將其抽象,但是查詢就不簡單了,對資料的關注度不一樣,所需要的查詢語句就不同,在針對查詢的方面,ORM 很難覆蓋全部的情況。
- 其次,物件導向中,存在著繼承,如果兩個物件存在繼承關係,那如何設計表結構,
目前的主流 ORM 技術有好多種,Hibernate 是一種比較典型的如上面所述的 ORM 技術,Mybatis 則是一種半自動化的 ORM 技術,這裡講一講 Mybatis
- Mybatis 不存在 Migration 功能,必須要通過第三方功能支援
- Mybatis 只做了 SQL 到物件的對映,類本身不代表資料表,而轉化出的物件都以 POJO 的形式提供。這實際上是一種欄位繫結
也就是說,ORM 本身,需要做兩件事
- 對映表的本身和遷移
- 屬性和資料庫的欄位繫結
Mybatis 由於過於依賴 SQL,因此如果將底層資料庫進行替換,則會導致很大的遷移工作量,Hibernate 就不存在這個問題,但是 Hibernate 確實不夠靈活,剛才也講到了 SQL 查詢的問題,因此 Hibernate 如果要做到靈活,實在是代價太大了。兩者各有優缺點。
ORM 的意義
ORM 主要有兩個意義
- 防止注入,保證 SQL 安全
- 抽象 OOP,便於開發
除了上面這兩種 ORM 以外,還有一種更加輕量級的技術方案,就是提供一整套類似於函式呼叫方式來寫 SQL 查詢,藉助 IDE 的程式碼提示和編譯器語法檢查,來保證安全,這種方案是靈活度最高的。但是更加繁瑣
在針對防注入方面,通常做法是使用繫結引數和預處理語句,避免字串的拼接,或者採用手段,防止傳入的單引號提前截斷 SQL
針對查詢的問題的想法
由於資料庫查詢存在這麼大的問題,而且需要保證 SQL 安全,筆者有兩條思路
- 封裝常用的操作,覆蓋大多數場景
- 提供安全的底層手段,解決特殊查詢情況