Gorm

AI 摘要: 对象关系映射(ORM)是一种技术,用于解决面向对象和关系数据库之间的不匹配现象。它相当于中继数据,通过将底层数据库的数据映射到软件应用层,实现了数据的交互和操作。ORM可以简化数据库操作,提高开发效率。参考资料:阮一峰ORM教程、Wiki ORM、GORM 文档

对象关系映射(英语: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优缺点

优点:

  1. ORM充当MVC架构中的Model层,架构也更清晰明了,让数据模块在同一个地方,易于维护
  2. ORM相关的工具包库提供了相关的数据标准化操作,比如SQL转义、事务、SQL预处理等
  3. 操作数据过程,调用起来更类似对象的操作,对研发来说,屏蔽了底层的SQL细节,避免了一些性能不佳的SQL

缺点:

  1. 针对复杂SQL,ORM性能存在一定的短板,ORM更偏向于解决简单关系(一对一、一对多、多对多)
  2. 对数据层的抽象,开发者无法了解底层的数据库操作,也无法定制一些特殊的SQL。
  3. 学习成本开销

Golang - GORM

主要特性

Gorm 是基于Golang语言在github开源上星最多的一个ORM库,其相关特性:

  1. ORM的的基本功能
  2. 关联支持(一对一、一对多、多对多)
  3. SQL钩子(在创建/保存/更新/删除/查找之前或之后执行事件)
  4. SQL预加载(提速SQL性能)
  5. 事务支持
  6. SQL 生成器
  7. 数据库自动迁移
  8. 自定义日志

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;

参考

  1. 阮一峰ORM教程:http://www.ruanyifeng.com/blog/2019/02/orm-tutorial.html
  2. Wiki ORM: https://zh.wikipedia.org/zh-cn/对象关系映射
  3. GORM 文档: https://gorm.io/zh_CN/docs/connecting_to_the_database.html