对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序设计技术,用于实现OOP编程语言里不同类型系统的数据之间的转换,通常是指"对象-关系映射"(Object/Relational Mapping)
面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别。为了解决这个不匹配的现象,对象关系映射技术应运而生。
ORM简要介绍
ORM相当于中继数据
简单的说,ORM相当于中继数据,实现了数据库中底层数据到软件应用层的数据映射

1
2
3
  | 数据库的表(table) --> 类(class)
记录(record,行数据)--> 对象(object)
字段(field)--> 对象的属性(attribute)
  | 
ORM优缺点
优点:
- ORM充当MVC架构中的Model层,架构也更清晰明了,让数据模块在同一个地方,易于维护
 - ORM相关的工具包库提供了相关的数据标准化操作,比如SQL转义、事务、SQL预处理等
 - 操作数据过程,调用起来更类似对象的操作,对研发来说,屏蔽了底层的SQL细节,避免了一些性能不佳的SQL
 
缺点:
- 针对复杂SQL,ORM性能存在一定的短板,ORM更偏向于解决简单关系(一对一、一对多、多对多)
 - 对数据层的抽象,开发者无法了解底层的数据库操作,也无法定制一些特殊的SQL。
 - 学习成本开销
 
Golang - GORM
主要特性
Gorm 是基于Golang语言在github开源上星最多的一个ORM库,其相关特性:
- ORM的的基本功能
 - 关联支持(一对一、一对多、多对多)
 - SQL钩子(在创建/保存/更新/删除/查找之前或之后执行事件)
 - SQL预加载(提速SQL性能)
 - 事务支持
 - SQL 生成器
 - 数据库自动迁移
 - 自定义日志
 
GORM - Code实践
创建gorm-learn环境
初始化自己项目环境(基于Module),项目目录:/data/go/proj/github.com/tkstorm/gorm-learn
gorm.Model介绍
gorm.Model是一个基本的GoLang结构,它包含以下字段:ID,CreatedAt,UpdatedAt,DeletedAt。
1
2
3
4
5
6
7
  | // gorm.Model definition
type Model struct {
  ID        uint `gorm:"primary_key"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt *time.Time
}
  | 
模型
模型定义
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  | // Inject fields `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt` into model `User`
type User struct {
  gorm.Model
  Name string
}
// Declaring model w/o gorm.Model
type User struct {
  ID   int
  Name string
}
  | 
模型中列定义标记
结构化标记用于在创建数据库或者插入数据记录时候,做出相应的SQL操作说明(比如主键、索引、字段声明、备注等等)
标签(grom:"xx-tag:xx-val") | 标签说明 | 
|---|
| Column | 指定列名 | 
| Type | 指定列数据类型 | 
| Size | 指定列大小, 默认值255 | 
| PRIMARY_KEY | 将列指定为主键 | 
| UNIQUE | 将列指定为唯一 | 
| DEFAULT | 指定列默认值 | 
| PRECISION | 指定列精度 | 
| NOT NULL | 将列指定为非 NULL | 
| AUTO_INCREMENT | 指定列是否为自增类型 | 
| INDEX | 创建具有或不带名称的索引, 如果多个索引同名则创建复合索引 | 
| UNIQUE_INDEX | 创建唯一索引 | 
| EMBEDDED | 将结构设置为嵌入 | 
| EMBEDDED_PREFIX | 设置嵌入结构的前缀 | 
| - | 忽略此字段 | 
模型中列的关联关系标记
参考:https://gorm.io/zh_CN/docs/models.html
主键
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  | type User struct {
  ID   int // field named `ID` will be used as primary field by default
  Name string
}
// Set field `AnimalID` as primary field
type Animal struct {
  AnimalID int64 `gorm:"primary_key"`
  Name     string
  Age      int64
}
  | 
表名
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
  | type User struct {} // default table name is `users`
// Set User's table name to be `profiles`
func (User) TableName() string {
  return "profiles"
}
func (u User) TableName() string {
    if u.Role == "admin" {
        return "admin_users"
    } else {
        return "users"
    }
}
// Disable table name's pluralization, if set to true, `User`'s table name will be `user`
db.SingularTable(true)
  | 
统一添加表名前缀 - DefaultTableNameHandler
1
2
3
  | gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string  {
    return "prefix_" + defaultTableName;
}
  | 
指定表名称操作(db.Table)
1
2
3
4
5
6
7
  | // Create `deleted_users` table with struct User's definition
db.Table("deleted_users").CreateTable(&User{})
var deleted_users []User
db.Table("deleted_users").Find(&deleted_users)
//// SELECT * FROM deleted_users;
db.Table("deleted_users").Where("name = ?", "jinzhu").Delete()
//// DELETE FROM deleted_users WHERE name = 'jinzhu';
  | 
列名
列名称将是该字段的名称是较低的蛇形列表
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  | type User struct {
  ID        uint      // column name is `id`
  Name      string    // column name is `name`
  Birthday  time.Time // column name is `birthday`
  CreatedAt time.Time // column name is `created_at`
}
// Overriding Column Name
type Animal struct {
    AnimalId    int64     `gorm:"column:beast_id"`         // set column name to `beast_id`
    Birthday    time.Time `gorm:"column:day_of_the_beast"` // set column name to `day_of_the_beast`
    Age         int64     `gorm:"column:age_of_the_beast"` // set column name to `age_of_the_beast`
}
  | 
列元素
CreatedAt:行记录创建时间
1
2
3
  | db.Create(&user) // will set `CreatedAt` to current time
// To change its value, you could use `Update`
db.Model(&user).Update("CreatedAt", time.Now())
  | 
UpdatedAt:行记录更新时间
1
2
  | db.Save(&user) // will set `UpdatedAt` to current time
db.Model(&user).Update("name", "jinzhu") // will set `UpdatedAt` to current time
  | 
DeletedAt:行记录删除时间
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  | db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// Batch Delete
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
// Delete record permanently with Unscoped
db.Unscoped().Delete(&order)
// DELETE FROM orders WHERE id=10;
  | 
参考
- 阮一峰ORM教程:http://www.ruanyifeng.com/blog/2019/02/orm-tutorial.html
 - Wiki ORM: https://zh.wikipedia.org/zh-cn/对象关系映射
 - GORM 文档: https://gorm.io/zh_CN/docs/connecting_to_the_database.html