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语言 - 极客兔兔
关注微博: @极客兔兔

相关文章
相关标签/搜索