补充

在默认表名添加其他前缀后缀

// 在默认表名前加sys_前缀

gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string  {
    return "sys_" + defaultTableName;
}


自定义表名:
func (模型) TableName() string{
    return "新的表名"
}

字段结构体对应规则

列名是字段名的蛇形小写
比如
* Age --> age
* CreatedTime --> create_time
* 可以通过gorm标签指定列名,AnimalId int64 gorm:"column:beast_id"

gorm.Model添加常用字段

在结构体中添加gorm.Model会自动添加以下三个字段
ID, CreatedAt, UpdatedAt, DeletedAt

type User struct{
    gorm.Model
    Name string
    Age int
}

gorm tag

多个属性值之间用分号分隔(英文的;):gorm:"size:64;not null"
-: 忽略,不映射这个字段 gorm:"-"
primary_key:主键 gorm:"primary_key"
AUTO_INCREMENT:自增 gorm:"AUTO_INCREMENT"
not null:不为空,默认为空 gorm:"not null"
index:索引, gorm:"index"
– 创建索引并命名: gorm:"index:idx_name_code"
– 优化查询,相当于图书的目录
unique_index:唯一索引 gorm:"unique_index"

  • unique:唯一 gorm:"unique"

  • column:指定列名 gorm:"column:user_name"

  • size:字符串长度,默认为255 gorm:"size:64"

  • type:设置sql类型 gorm:"type:varchar(100)" // 不推荐直接改类型

  • default default:'galeone' 默认值

DB接口

  • First按照主键顺序的第一条记录
// 按照主键顺序的第一条记录,(主键升序)

var user model.User
result := db.First(&user)
fmt.Println(user)

result.RowsAffected // 返回找到的记录数
result.Error        // returns error

// sql语句:SELECT * FROM users ORDER BY id LIMIT 1;
  • FirstOrCreate找到就返回,没找到则创建
// 未找到 user,则根据给定条件创建一条新纪录
var user model.User
db.FirstOrCreate(&user, User{Name: "xiaosheng"})

// 找到了 `name` = `xiaosheng` 的 user
db.Where(User{Name: "xiaosheng"}).FirstOrCreate(&user)
  • Last最后一条记录
// 获取最后一条记录(主键降序)
var user model.User
// 按照主键顺序的最后一条记录
db.Last(&user)
fmt.Println(user)
// sql语句:SELECT * FROM users ORDER BY id DESC LIMIT 1;
  • Take获取一条记录
// 获取一条记录,没有指定排序字段
var user model.User
db.Take(&user)

// sql语句:SELECT * FROM users LIMIT 1;
  • Find
var user model.User
// 所有记录
db.Find(&users, []int{1,2,3})
// sql语句:// SELECT * FROM users WHERE id IN (1,2,3);

result := db.Find(&users)
// sql语句:SELECT * FROM users;

// 根据指定条件查询
db.Find(&user, "name = ?", "hallen")

//或者结合where
db.Where("name = ?", "hallen").Find(&users)
// sql语句:SELECT * FROM users WHERE name = 'hallen';
db.Where("name LIKE ?", "%ha%").Find(&users)
// sql语句:SELECT * FROM users WHERE name LIKE '%hal%';
  • Where
var user model.User


// 根据条件查询得到满足条件的第一条记录
db.Where("role_id = ?", "2").First(&user)
fmt.Println(user)

var users []model.User

// 根据条件查询得到满足条件的所有记录
db.Where("user_id = ?", "1").Find(&users)
fmt.Println(users)

// like模糊查询
db.Where("role_id like ?", "%2").Find(&users)
fmt.Println(users)

db.Where("updated_at > ?", "2019-02-08 18:08:27").Find(&users)
fmt.Println(users)

// struct结构查询条件
db.Where(&DqmUserRole{RoleId: "1,2", UserId: "1"}).First(&user)
fmt.Println(user)

条件:
=
LIKE
IN:Where("name IN ?", []string{"hallen", "hallen2"})
AND:Where("name = ? AND age >= ?", "jinzhu", "22")
Time:Where("updated_at > ?", lastWeek)
BETWEEN:Where("created_at BETWEEN ? AND ?", lastWeek, today)
  • select指定要从数据库检索的字段
db.Select("name, age").Find(&users)
//// SELECT name, age FROM users;

db.Select([]string{"name", "age"}).Find(&users)
//// SELECT name, age FROM users;

db.Table("users").Select("COALESCE(age,?)", 42).Rows()    // COALESCE:聚合
//// SELECT COALESCE(age,'42') FROM users;
  • Create
user := models.User{Name:"李四",Age:18,Addr:"xxx",Pic:"/static/upload/pic111.jpg",Phone:"13411232312"}
result := db.Create(&user)

user.ID             // 返回插入数据的主键
result.Error        // 返回 error
result.RowsAffected // 返回插入记录的条数

不支持批量插入

  • save
var user model.User

db.First(&user)

user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
  • update
var users []model.User
db.Where("active = ?", true).find(&users).Update("name", "hello")


db.Where("active = ?", true).find(&users).Updates(User{Name: "hello", Age: 18})


// update也可以使用map:map[string]interface{}{"name": "hello", "age": 18}

// 也可以使用save更新
  • delete
db.Delete(&user,1)

// 批量删除
db.Where("age = ?", 20).Delete(&User{})
  • Unscoped:软删除
    // 也就是逻辑删除    
    // gorm.Model 将DeletedAt 字段设置为当前时间
    // 需要再模型中指定

    type User struct {
      ID      int
      Deleted `gorm:"DeletedAt"`      // 如果设置了所有的删除都将是逻辑删除
      Name    string
    }

    // 在查询时会忽略被软删除的记录
    db.Where("age = 20").Find(&user)
    // SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;


    // 查询逻辑删除的数据
    db.Unscoped().Where("age = 20").Find(&users)
    // SELECT * FROM users WHERE age = 20;

    // 想要物理删除的办法
    db.Unscoped().Delete(&user)
  • not
var user model.User

db.Not(User{Name: "hallen", Age: 18}).First(&user)

// SELECT * FROM `users`  WHERE (`users`.`name` <> 'hallen6') AND (`users`.`age` <> 19);
  • Or
var users []model.User


db.Where("name = 'hallen'").Or(User{Name: "hallen2", Age: 18}).Find(&users)
// SELECT * FROM users WHERE name = 'hallen' OR (name = 'jinzhu 2' AND age = 18);
  • Order
var users []model.User
db.Order("age desc").Find(&users) // 注意这里的order要在find前面,否则不生效
fmt.Println(users)

// SELECT * FROM users ORDER BY age desc;

默认为asc
  • Limit和Offset
var users []model.User


db.Limit(3).Find(&users)  // 三条
// SELECT * FROM users LIMIT 3;

db.Limit(10).Offset(5).Find(&users) // 从5开始的10条数据
// SELECT * FROM users OFFSET 5 LIMIT 10;
  • Scan
type Result struct {
        Id int64
    }
var results []Result
db.Select("id").Where("user_id in (?)", []string{"1", "2"}).Find(&dqmUserRole20).Scan(&results)
fmt.Println(results)
  • Count
db.Where("name = ?", "hallen").Find(&users).Count(&count)
// SELECT count(*) FROM users WHERE name = 'jinzhu'

db.Model(&User{}).Where("name = ?", "jinzhu").Count(&count)
// SELECT count(*) FROM users WHERE name = 'jinzhu'; (count)

db.Table("deleted_users").Count(&count)
// SELECT count(*) FROM deleted_users;
  • Group & Having
    GROUP BY语句用来与聚合函数(aggregate functions such as COUNT, SUM, AVG, MIN, or MAX.)联合使用,只返回一个单个值

HAVING语句通常与GROUP BY语句联合使用,用来过滤由GROUP BY语句返回的记录集。

HAVING语句的存在弥补了WHERE关键字不能与聚合函数联合使用的不足

   type result struct {
      Date  time.Time
      Total int
    }

    db.Select("name, count(*)").Group("name").Find(&result)

    // select name,count(*) FROM users GROUP BY `age`

    db.Select("name, count(*)").Group("name").Having("add = ?","xxx").Find(&result)


  // select name,count(*) FROM users GROUP BY `age` 后面不能用where限制条件,只能使用having

 // select name,count(age) FROM users GROUP BY `age` HAVING addr='xxx'
  • Join
    left join: 以左面表为标准
    right join: 以右面表为标准
db.Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&result{})

高级查询

  • FirstOrInit和Attrs

FirstOrInit:获取第一个匹配的记录,或者使用给定的条件初始化一个新的记录(仅适用于struct,map条件)

Attrs:如果没有找到记录,则使用Attrs中的数据来初始化一条记录:

var user model.User

// 查不到该条记录,则使用attrs值替换,// 查到记录,则使用数据库中的值
db.Where(User{Name:"xiaosheng"}).Attrs(User{Name:"xiaosheng",Age:18}).FirstOrInit(&user)
  • FirstOrInit和Assign

Assign:不管是否找的到,最终返回结构中都将带上Assign指定的参数,有则代替,没有则添加

var user model.User

// 不管是否找到对应记录,使用Assign值替代查询到的值
db.Where("id = ?", "1").Assign(model.User{Id: "15"}).FirstOrInit(&user)
  • Pluck

Pluck 用于从数据库查询单个列,并将结果扫描到切片。如果您想要查询多列,您应该使用 Select 和 Scan

    var ages []int64
    db.Find(&users).Pluck("age", &ages)

    var names []string
    db.Model(&User{}).Pluck("name", &names)


    // 超过一列的查询,应该使用 `Scan` 或者 `Find`,例如:
    db.Select("name", "age").Scan(&users)
    db.Select("name", "age").Find(&users)
  • Scopes

Scopes 允许你指定常用的查询,可以在调用方法时引用这些查询

func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
  return db.Where("amount > ?", 1000)
}

func PaidWithCreditCard(db *gorm.DB) *gorm.DB {
  return db.Where("pay_mode_sign = ?", "C")
}

func PaidWithCod(db *gorm.DB) *gorm.DB {
  return db.Where("pay_mode_sign = ?", "C")
}

func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
  return func (db *gorm.DB) *gorm.DB {
    return db.Where("status IN (?)", status)
  }
}

db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
// 查找所有金额大于 1000 的信用卡订单

db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)
// 查找所有金额大于 1000 的货到付款订单

db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
// 查找所有金额大于 1000 且已付款或已发货的订单
  • LogMode

Gorm有内置的日志记录器支持,默认情况下,它会打印发生的错误。

// 启用Logger,显示详细日志

db.LogMode(true)

// 也可以查看单语句的信息

db.Debug().Where("name = ?", "xiaosheng").First(&User{})

错误处理

错误种类

  • RecordNotFound:查询不到数据,不适用于切片

  • ErrInvalidSQL:无效sql

  • ErrInvalidTransaction:事务有错

  • ErrCantStartTransaction:无法开启事务,出现在使用Begin的情况下

  • ErrUnaddressable:使用不可寻址的值,传递的指针值不对

单个错误

err := db.Where("name = ?", "小生").First(&user).Error
if err != nil {
  // 错误处理
}

// 或者

result := db.Where("name = ?", "xiaosheng").First(&user)

if result.Error != nil {
  // 错误处理
}

处理多个错误GetErrors

errors := db.First(&user).Limit(10).Find(&users).GetErrors()
fmt.Println(len(errors)) // 打印错误数量

// 遍历错误内容
for _, err := range errors {
  fmt.Println(err)
}

事务

db.Begin() 声明开启事务,结束的时候调用 tx.Commit(),异常的时候调用 tx.Rollback()
ct := db.Begin() // 开启事务
ret3 := ct.Commit()

if ret3.Error != nil {
    ct.Rollback()   // 回滚
}

原生sql

增改删Exec

// 增
db.Exec("insert into users (name,age) values(?,?)","hallen222",111)
// 改
db.Exec("update users set name = ? where id = ?","hallen111",1)
// 删
db.Exec("delete from  users where id = ?",1)

var users []relate_tables.User
db.Raw("select * from users").Find(&users)

返回单条数据Row

row,_ := db.Raw("select * from users").Row()

返回多条数据Rows

row,_ := db.Raw("select * from users").Rows()
分类: go

站点统计

  • 文章总数:315 篇
  • 分类总数:20 个
  • 标签总数:193 个
  • 运行天数:1165 天
  • 访问总数:52937 人次

浙公网安备33011302000604

辽ICP备20003309号