7天用Go動手寫/從零實現ORM框架GeeORM

0 目錄

1 談談 ORM 框架

對象關係映射(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 個字段 NameAge;第二條 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)...

2 關於 GeeORM

數據庫的特性很是多,簡單的增刪查改使用 ORM 替代 SQL 語句是沒有問題的,可是也有不少特性難以用 ORM 替代,好比複雜的多表關聯查詢,ORM 也可能支持,可是基於性能的考慮,開發者本身寫 SQL 語句極可能更高效。

所以,設計實現一個 ORM 框架,就須要給功能特性排優先級了。

Go 語言中使用比較普遍 ORM 框架是 gormxorm。除了基礎的功能,好比表的操做,記錄的增刪查改,gorm 還實現了關聯關係(一對1、一對多等),回調插件等;xorm 實現了讀寫分離(支持配置多個數據庫),數據同步,導入導出等。

gorm 正在完全重構 v1 版本,短時間內看不到發佈 v2 的可能。相比於 gorm-v1,xorm 在設計上更清晰。GeeORM 的設計主要參考了 xorm,一些細節上的實現參考了 gorm。GeeORM 的目的主要是瞭解 ORM 框架設計的原理,具體實現上魯棒性作得不夠,一些複雜的特性,例如 gorm 的關聯關係,xorm 的讀寫分離沒有實現。目前支持的特性有:

  • 表的建立、刪除、遷移。
  • 記錄的增刪查改,查詢條件的鏈式操做。
  • 單一主鍵的設置(primary key)。
  • 鉤子(在建立/更新/刪除/查找以前或以後)
  • 事務(transaction)。
  • ...

GeeORM 分7天實現,天天完成的部分都是能夠獨立運行和測試的,就像搭積木同樣,一個個獨立的特性組合在一塊兒就是最終的 ORM 框架。天天的代碼在 100 行左右,同時配有較爲完備的單元測試用例。

附 推薦閱讀

原文地址: 7天用Go從零實現ORM框架GeeORM - 極客兔兔
知乎專欄: Go語言 - 極客兔兔
關注微博: @極客兔兔

相關文章
相關標籤/搜索