對象關係映射(Object Relational Mapping,簡稱ORM)是經過使用描述對象和數據庫之間映射的元數據,將面嚮對象語言程序中的對象自動持久化到關係數據庫中。
那對象和數據庫是如何映射的呢?html
數據庫 | 面向對象的編程語言 |
---|---|
表(table) | 類(class/struct) |
記錄(record, row) | 對象 (object) |
字段(field, column) | 對象屬性(attribute) |
舉一個具體的例子,來理解 ORM。git
CREATE TABLE `User` (`Name` text, `Age` integer); INSERT INTO `User` (`Name`, `Age`) VALUES ("Tom", 18); SELECT * FROM `User`;
第一條 SQL 語句,在數據庫中建立了表 User
,而且定義了 2 個字段 Name
和 Age
;第二條 SQL 語句往表中添加了一條記錄;最後一條語句返回表中的全部記錄。github
假如咱們使用了 ORM 框架,能夠這麼寫:golang
type User struct { Name string Age int } orm.CreateTable(&User{}) orm.Save(&User{"Tom", 18}) var users []User orm.Find(&users)
ORM 框架至關於對象和數據庫中間的一個橋樑,藉助 ORM 能夠避免寫繁瑣的 SQL 語言,僅僅經過操做具體的對象,就可以完成對關係型數據庫的操做。sql
那如何實現一個 ORM 框架呢?數據庫
CreateTable
方法須要從參數 &User{}
獲得對應的結構體的名稱 User 做爲表名,成員變量 Name, Age 做爲列名,同時還須要知道成員變量對應的類型。Save
方法則須要知道每一個成員變量的值。Find
方法僅從傳入的空切片 &[]User
,獲得對應的結構體名也就是表名 User,並從數據庫中取到全部的記錄,將其轉換成 User 對象,添加到切片中。若是這些方法只接受 User 類型的參數,那是很容易實現的。可是 ORM 框架是通用的,也就是說能夠將任意合法的對象轉換成數據庫中的表和記錄。例如:編程
type Account struct { Username string Password string } orm.CreateTable(&Account{})
這就面臨了一個很重要的問題:如何根據任意類型的指針,獲得其對應的結構體的信息。這涉及到了 Go 語言的反射機制(reflect),經過反射,能夠獲取到對象對應的結構體名稱,成員變量、方法等信息,例如:app
typ := reflect.Indirect(reflect.ValueOf(&Account{})).Type() fmt.Println(typ.Name()) // Account for i := 0; i < typ.NumField(); i++ { field := typ.Field(i) fmt.Println(field.Name) // Username Password }
reflect.ValueOf()
獲取指針對應的反射值。reflect.Indirect()
獲取指針指向的對象的反射值。(reflect.Type).Name()
返回類名(字符串)。(reflect.Type).Field(i)
獲取第 i 個成員變量。除了對象和表結構/記錄的映射之外,設計 ORM 框架還須要關注什麼問題呢?框架
1)MySQL,PostgreSQL,SQLite 等數據庫的 SQL 語句是有區別的,ORM 框架如何在開發者不感知的狀況下適配多種數據庫?編程語言
2)如何對象的字段發生改變,數據庫表結構可以自動更新,便是否支持數據庫自動遷移(migrate)?
3)數據庫支持的功能不少,例如事務(transaction),ORM 框架能實現哪些?
4)...
數據庫的特性很是多,簡單的增刪查改使用 ORM 替代 SQL 語句是沒有問題的,可是也有不少特性難以用 ORM 替代,好比複雜的多表關聯查詢,ORM 也可能支持,可是基於性能的考慮,開發者本身寫 SQL 語句極可能更高效。
所以,設計實現一個 ORM 框架,就須要給功能特性排優先級了。
Go 語言中使用比較普遍 ORM 框架是 gorm 和 xorm。除了基礎的功能,好比表的操做,記錄的增刪查改,gorm 還實現了關聯關係(一對1、一對多等),回調插件等;xorm 實現了讀寫分離(支持配置多個數據庫),數據同步,導入導出等。
gorm 正在完全重構 v1 版本,短時間內看不到發佈 v2 的可能。相比於 gorm-v1,xorm 在設計上更清晰。GeeORM 的設計主要參考了 xorm,一些細節上的實現參考了 gorm。GeeORM 的目的主要是瞭解 ORM 框架設計的原理,具體實現上魯棒性作得不夠,一些複雜的特性,例如 gorm 的關聯關係,xorm 的讀寫分離沒有實現。目前支持的特性有:
GeeORM
分7天實現,天天完成的部分都是能夠獨立運行和測試的,就像搭積木同樣,一個個獨立的特性組合在一塊兒就是最終的 ORM 框架。天天的代碼在 100 行左右,同時配有較爲完備的單元測試用例。
原文地址: 7天用Go從零實現ORM框架GeeORM - 極客兔兔
知乎專欄: Go語言 - 極客兔兔
關注微博: @極客兔兔