对象关系映射(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语言 - 极客兔兔
关注微博: @极客兔兔