补充
在默认表名添加其他前缀后缀
// 在默认表名前加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
:字符串长度,默认为255gorm:"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()