优秀的编程知识分享平台

网站首页 > 技术文章 正文

gorm 笔记(gorm入门)

nanyue 2024-09-09 04:57:50 技术文章 7 ℃

gorm 是 golang web 编程中十分常用的数据库关系映射库.

gorm 简介

ORM (Object Relational Mapping) 是实现程序对象到关系数据库的一种映射. 它可以使得编程语言能高效操作数据. ORM 具有简单、精确、易懂、易用的特点.

GORM 是 jinzhu 大神开发的 go 语言 ORM 框架,也是目前 golang 中最常用的 ORM 框架. jinzhu 大神目前正在筹划 gorm 2.0. 作为 go web 开发者,是十分有必要了解 gorm 库的.

gorm 实现了几乎所有 ORM 框架的特性, 它的特性涵盖:

  • 关联(包含一个,包含多个,属于,多对多,多种包含)
  • Callbacks(创建/保存/更新/删除/查找之前/之后)
  • 预加载(急加载)
  • 事务
  • ?复合主键
  • SQL Builder(它可以生成 sql 语句的函数库)
  • 自动迁移(表结构的增量修改)
  • 日志
  • 可扩展,编写基于GORM回调的插件
  • 每个功能都有测试
  • 开发人员友好

gorm 基础操作

2.1 CRUD 操作

连接数据库, 首先需要通过 gorm 连接数据库,使用 gorm.Open() 函数进行连接,并导入相应的驱动,以及连接字符串 connection,如 mysql , 如下:

import (
    "github.com/jinzhu/gorm"
     _ "github.com/jinzhu/gorm/dialects/mysql"
)

func main() {
  db, err := gorm.Open("mysql",
     "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
  defer db.Close()
}

创建数据表, 可以通过 gorm.DB.CreateTable 进行表的创建. 如下:

// 为模型`User`创建表
db.CreateTable(&User{})
// 创建表`users'时将“ENGINE = InnoDB”附加到SQL语句
db.Set("gorm:table_options", "ENGINE=InnoDB").CreateTable(&User{})

更新数据表

根据对象的值更新数据库的记录

db.First(&user)
user.Age = 100
db.Save(&user)

更新对象的非零值( golang 的每个类型都有零值)到数据库中

db.Updates(&product)

更新全部字段(根据主键)

db.Select("*").Updates(&product)

更新除了某个字段外的其它字段

db.Omit("*").Updates(&product)

更新特定字段

db.Select("code", "Price").Updates(&product)

更新除 code 外的非零值字段

db.Omit("Code").Updates(&product)

更新除 code 外的全部字段

db.Select("*").Omit("Code").Updates(&product)

更新指定字段

db.Select("Price").Updates(map[string]interface{"Price": 200,
   "Name":"T-shirt"})

删除数据表

删除记录,需要确保主要字段(主键)不为空,否则将删除模型的所有记录

db.Delete(&email)

删除所有匹配的记录

db.Where("email LIKE ?", "%pilatus%").Delete(Email{})

2.2 关联

关系型数据库的表可以存在多种关联关系,如:

  1. 一对一: one_to_one,包括 has_one 或 belongs_to
  2. 一对多: one_to_many, 包括 has_many、belongs_to
  3. 多对多: many_to_many

gorm 在进行数据表多关联定义时,也支持关联定义. 下面的代码中,User 拥有一个 Account(has one) ,拥有多个 Pets (has many), 多个 Toys(has many),属于某个 Company(belongs to),属于某 Manager(belongs to),会多种 languages(many to many),拥有很多 friends(many to many 单表),Pet 有一个玩具 Toy(has one 多态)

type User struct {
  gorm.Model
  Name      string
  Account   Account
  Pets      []*Pet
  Toys      []Toy      `gorm:"polymorphic:Owner"`
  CompanyID *int
  Company   Company
  ManagerID *uint
  Manager   *User
  Team      []User     `gorm:"foreignkey:ManagerID;""`
  Languages []Language `gorm:"many2many:UserSpeak;""`
  Friends   []*User    `gorm:"many2many:user_friends;""`
}

type Account struct {
  gorm.Model
}

type Company struct {
  gorm.Model
}

type Pet struct {
  gorm.Model
  UserID int
  Toy    Toy `gorm:"polymorphic:Owner;"`
}

gorm 进阶用法

3.1 preload 预加载

gorm 提供 Preload 可以预加载数据,使用方式如下:

type User struct{
   gorm.Model
   Profile Profile
   Orders []Order   
}

type Order struct{
   gorm.Model
   State string      
}

db.Preload("Orders").Find(&user)

db.Preload("Orders","state NOT IN(?)", "cancelled").Find(&user)

db.Preload("Orders.CreditCard").Find(&users)

db.Joins("Profile").Find(&users)

3.2 migrate

gorm 提供了 migrator 用于更新数据库表结构, gorm 2.0 即将提供 migrator. 通过 AutoMigrate 可以将表结构自动进行更新,但是为了保护数据并不会改变现有列的类型或删除未使用的列,其用法如下:

db.AutoMigrate(&User{})

db.AutoMigrate(&User{}, &Product{}, &Order{})

// 创建表时添加表后缀
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})

3.3 勾子(hook)

在 gorm 的使用过程中,可能涉及 map 等复杂数据类型与数据库 model 字段的绑定. 这些可以通过勾子(hook) 实现. 如下述代码所示:

// Save 保存前/后
func (u *User) BeforeSave(tx *gorm.DB) (err error)

// Create 创建前/后
func (u *User) AfterCreate(tx *gorm.DB) (err error)

// Update 更新数据前/后
func (u *User) BeforeUpdate(tx *gorm.DB) (err error)

// Before/After Delete 更新数据前后调用
func (u *User) AfterDelete(tx *gorm.DB) (err error)

// 查询数据后调用
func (u *User) AfterFind(tx *gorm.DB) (err error)

3.4 sql/database

gorm 连接数据库需要使用相应数据库的 go 语言驱动,如 mysql、postgresql、sqlite、mssql 等. 为了方便使用,gorm 封装了这些驱动到 gorm package 中. 如:

github.com/jinzhu/gorm/dialects/mysql
github.com/jinzhu/gorm/dialects/postgres
github.com/jinzhu/gorm/dialects/sqlite
github.com/jinzhu/gorm/dialects/mssql

3.5 事物

对于一系列的 sql 操作,可以使用事务进行, gorm 提供的事务流程如下:

// 开始事务
tx := db.Begin()

// 在事务中做一些数据库操作(从这一点使用'tx',而不是'db')
tx.Create(...)

// ...

// 发生错误时回滚事务
tx.Rollback()

// 或提交事务
tx.Commit()

// 例子如下
func CreateAnimals(db *gorm.DB) err {
  tx := db.Begin()
  // 注意,一旦你在一个事务中,使用tx作为数据库句柄

  if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
     tx.Rollback()
     return err
  }

  if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
     tx.Rollback()
     return err
  }

  tx.Commit()
  return nil
}

3.6 代码复用

gorm 提供了代码复用机制,可以提升编码效率,让不通对象相似功能的可以复用代码. 例子如下:

func Paginate(r *http.Request) func(*gorm.DB) *gorm.DB{
  return func(db *gorm.DB) *gorm.DB{
     return db.Offset(offset).Limit(perPage)     
  }
}

// 复用上述d代码
db.Scopes(Paginate(r)).Find(&users)
db.Scopes(Paginate(r)).Find(&articles)
db.Scopes(Paginate(r)).Find(&products

END

4.1 插件系统

  • 扩展 API
  • 基于插件系统的功能
  • 定制 GORM 功能

4.2 参考资料

1. gorm 介绍与展望 https://talkgo.org/night/81-2020-03-19-gorm-guide/

Tags:

最近发表
标签列表