gorm快速使用

bytemode · 2019-12-26 19:03:28 · 7662 次点击 · 预计阅读时间 6 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2019-12-26 19:03:28 的文章,其中的信息可能已经有所发展或是发生改变。

gorm

ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping) 的缩写. gorm, github.com/jinzhu/gorm 全特性 ORM (几乎包含所有特性).

模型定义

模型一般都是普通的 Golang 的结构体,Go 的基本数据类型,或者指针。sql.Scanner 和 driver.Valuer,同时也支持接口。

gorm.Model

gorm.Model 是一个包含一些基本字段的结构体,包含的字段有 ID,CreatedAt, UpdatedAt, DeletedAt。 你可以用它来嵌入到你的模型中,或者也可以用它来建立自己的模型.GORM 默认使用 ID 作为主键名。

  • 可以通过`gorm:"primary_key"设置主键.
  • 表名是结构体名称的复数形式, type User struct{} 默认表名是"users", 可以重写TableName() string 返回新表名
  • 禁用复数表名:db.SingularTable(true)
  • 修改默认表名gorm.DefaultTableNameHandler
    gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string  {
      return "prefix_" + defaultTableName;
    }
    
  • 蛇形列名,列名是字段名的蛇形小写形式
      type User struct {
      ID        uint      // 字段名是 `id`
      Name      string    // 字段名是 `name`
      Birthday  time.Time // 字段名是 `birthday`
      CreatedAt time.Time // 字段名是 `created_at`
      }
    

结构标签

标签 说明
Column 指定列的名称
Type 指定列的类型
Size 指定列的大小,默认是 255
PRIMARY_KEY 指定一个列作为主键
UNIQUE 指定一个唯一的列
DEFAULT 指定一个列的默认值
PRECISION 指定列的数据的精度
NOT NULL 指定列的数据不为空
AUTO_INCREMENT 指定一个列的数据是否自增
INDEX 创建带或不带名称的索引,同名创建复合索引
UNIQUE_INDEX 类似 索引,创建一个唯一的索引
EMBEDDED 将 struct 设置为 embedded
EMBEDDED_PREFIX 设置嵌入式结构的前缀名称

  • 忽略这些字段
    FOREIGNKEY 指定外键
type User struct {
  gorm.Model
  Name         string `gorm:"default:aa"`
  Age          sql.NullInt64
  Birthday     *time.Time `gorm:"column:day_of_the_beast"`
  Email        string  `gorm:"type:varchar(100);unique_index"`
  Role         string  `gorm:"size:255"` //设置字段的大小为255个字节
  MemberNumber *string `gorm:"unique;not null"` // 设置 memberNumber 字段唯一且不为空
  Num          int     `gorm:"AUTO_INCREMENT"` // 设置 Num字段自增
  Address      string  `gorm:"index:addr"` // 给Address 创建一个名字是  `addr`的索引
  IgnoreMe     int     `gorm:"-"` //忽略这个字段
}

CRUD

连接

import (
    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
)

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

创建记录

user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
db.Create(&user)

//在钩子中设置字段值
func (user *User) BeforeCreate(scope *gorm.Scope) error {
  scope.SetColumn("ID", uuid.New())
  return nil
}

查询记录

db.First()
db.Find()
db.Where().Find()
db.Raw()
db.Exec()

// 获取第一条记录,按主键排序
db.First(&user) // SELECT * FROM users ORDER BY id LIMIT 1;

// 获取所有的记录
db.Find(&users) // SELECT * FROM users;

// 通过主键进行查询
db.First(&user, 10) // SELECT * FROM users WHERE id = 10;

// 原生 SQL
db.Find(&user, "name = ?", "jinzhu") // SELECT * FROM users WHERE name = "jinzhu";

db.Find(&users, "name <> ? AND age > ?", "jinzhu", 20) // SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;

// Struct
db.Find(&users, User{Age: 20}) // SELECT * FROM users WHERE age = 20;

// 获取第一条匹配的记录
db.Where("name = ?", "jinzhu").First(&user) // SELECT * FROM users WHERE name = 'jinzhu' limit 1;

// 获取所有匹配的记录
db.Where("name = ?", "jinzhu").Find(&users) // SELECT * FROM users WHERE name = 'jinzhu';

//struct
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user) // SELECT * FROM users WHERE name = "jinzhu" AND age = 20 LIMIT 1;

// Map
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users) // SELECT * FROM users WHERE name = "jinzhu" AND age = 20;


type Result struct {
    Name string
    Age  int
}

var result Result
db.Table("users").Select("name, age").Where("name = ?", 3).Scan(&result)

// Raw SQL
db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result)

更新记录

db.Save() //更新所有字段
db.Model(&struct).Update(k,v) //更新特定字段

db.First(&user)
user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
//// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;

// 如果单个属性被更改了,更新它
db.Model(&user).Update("name", "hello")
//// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;

删除记录

// 删除一条存在的记录
db.Delete(&email)
db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})

高级

钩子

钩子是一个在 插入 / 查询 / 更新 / 删除 之前或之后被调用的方法。
如果你在一个模型中定义了特殊的方法,它将会在插入,更新,查询,删除的时候被自动调用,如果任何的回调抛出错误,GORM 将会停止将要执行的操作并且回滚当前的改变
在 GORM 中的保存 / 删除 操作会默认进行事务处理,所以在事物中,所有的改变都是无效的,直到它被提交为止
可用于更新的钩子:
// 开启事务
BeforeSave
BeforeUpdate
AfterUpdate
AfterSave
// 提交或回滚的事务

func (u *User) BeforeSave() (err error) {
    if u.IsValid() {
        err = errors.New("can't save invalid data")
    }
    return
}

func (u *User) AfterCreate(scope *gorm.Scope) (err error) {
    if u.ID == 1 {
    scope.DB().Model(u).Update("role", "admin")
  }
    return
}

func (u *User) BeforeUpdate() (err error) {
    if u.readonly() {
        err = errors.New("read only user")
    }
    return
}

// 在事务结束后,进行更新数据
func (u *User) AfterUpdate(tx *gorm.DB) (err error) {
  if u.Confirmed {
    tx.Model(&Address{}).Where("user_id = ?", u.ID).Update("verfied", true)
  }
    return
}

// 在事务结束后进行更新数据
func (u *User) AfterDelete(tx *gorm.DB) (err error) {
  if u.Confirmed {
    tx.Model(&Address{}).Where("user_id = ?", u.ID).Update("invalid", false)
  }
    return
}

事务

GORM 默认在事务中执行单个 create, update, delete 操作,以确保数据库数据完整性。

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

// 在事务中执行一些数据库操作 (从这里开始使用 'tx',而不是 'db')
tx.Create(...)

// ...

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

// 或者提交这个事务
tx.Commit()

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

7662 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传