连接数据库
gorm维护了一个连接池,初始化db之后所有的连接都由库来管理,不需要使用者手动关闭。
注册单例之后就可以一直用。
创建
type User struct {
ID int64
Name string
Age int64
}
使用使用NewRecord()查询主键是否存在,主键为空使用Create()创建记录:
user := User{Name: "xxx", Age: 18}
db.NewRecord(user) // 主键为空返回`true`
db.Create(&user) // 创建user
Debug():用来查看详细sql
默认值
可以通过 tag 定义字段的默认值,比如:
type User struct {
ID int64
Name string `gorm:"default:'xxx'"`
Age int64
}
注意: 在创建记录时候生成的 SQL 语句会排除没有值或值为零值的字段。 在将记录插入到数据库后,Gorm会从数据库加载那些字段的默认值。
举个例子:
var user = User{Name: "", Age: 99}
db.Create(&user)
上面代码实际执行的SQL语句是INSERT INTO users("age") values('99');,排除了零值字段Name,而在数据库中这一条数据会使用设置的默认值xxx作为Name字段的值。
注意: 所有字段的零值, 比如0, "",false或者其它零值,都不会保存到数据库内,但会使用他们的默认值。
如果想避免这种情况,可以考虑使用指针或实现 Scanner/Valuer接口,比如:
使用指针方式实现零值存入数据库
// 使用指针
type User struct {
ID int64
Name *string `gorm:"default:'xxx'"`
Age int64
}
user := User{Name: new(string), Age: 18))}
db.Create(&user) // 此时数据库中该条记录name字段的值就是''
使用Scanner/Valuer接口方式实现零值存入数据库
// 使用 Scanner/Valuer
type User struct {
ID int64
Name sql.NullString `gorm:"default:'xxx'"` // sql.NullString 实现了Scanner/Valuer接口
Age int64
}
user := User{Name: sql.NullString{"", true}, Age:18}
db.Create(&user) // 此时数据库中该条记录name字段的值就是''
map[string]interface{}:实现字符串类型的map接口
查询
// 根据主键查询第一条记录
db.First(&user)
//// SELECT * FROM users ORDER BY id LIMIT 1;
// 随机获取一条记录
db.Take(&user)
//// SELECT * FROM users LIMIT 1;
// 根据主键查询最后一条记录
db.Last(&user)
//// SELECT * FROM users ORDER BY id DESC LIMIT 1;
// 查询所有的记录
db.Find(&users)
//// SELECT * FROM users;
// 查询指定的某条记录(仅当主键为整型时可用)
db.First(&user, 10)
//// SELECT * FROM users WHERE id = 10;
Struct & Map查询的where
// 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;
// 主键的切片
db.Where([]int64{20, 21, 22}).Find(&users)
//// SELECT * FROM users WHERE id IN (20, 21, 22);
Attrs如果记录未找到,将使用参数初始化 struct.
Assign不管记录是否找到,都将参数赋值给 struct.
FirstOrInit获取匹配的第一条记录,否则根据给定的条件初始化一个新的对象 (仅支持 struct 和 map 条件)
子查询是基于 *gorm.expr的子查询
db.Where("amount > ?", db.Table("orders").Select("AVG(amount)").Where("state = ?", "paid").SubQuery()).Find(&orders)
// SELECT * FROM "orders" WHERE "orders"."deleted_at" IS NULL AND (amount > (SELECT AVG(amount) FROM "orders" WHERE (state = 'paid')));
Select指定从数据库中检索出的字段,默认会选择全部字段。
db.Select("name, age").Find(&users)
// SELECT name, age FROM users;
Limit,指定从数据库检索出的最大记录数。
Offset,指定开始返回记录前要跳过的记录数。
Count,该 model 能获取的记录总数。但Count 必须是链式查询的最后一个操作 ,因为它会覆盖前面的 SELECT,但如果里面使用了 count 时不会覆盖
更新
Save()默认会更新该对象的所有字段,即使没有赋值
如果你只想更新指定字段,可以使用Update或者Updates
db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
db.Model(&user).Omit("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
以上更新操作会自动运行 model 的 BeforeUpdate, AfterUpdate 方法,更新 UpdatedAt 时间戳, 在更新时保存其 Associations, 如果不想调用这些方法,可以使用 UpdateColumn, UpdateColumns
使用 struct 更新时,只会更新非零值字段,若想更新所有字段,使用map[string]interface{}
可以使用 RowsAffected 获取更新记录总数
删除
删除记录时,要确保主键字段有值,GORM 会通过主键去删除记录,如果主键为空,GORM 会删除该 model 的所有记录。
软删除
如果 model 有 DeletedAt 字段,就意味着有软删除的功能
当调用 Delete 方法时, 记录不会真正的从数据库中被删除, 会将DeletedAt 字段的值会被设置为当前时间
db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// 批量删除
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
// 查询记录时会忽略被软删除的记录
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
// Unscoped 方法可以查询被软删除的记录
db.Unscoped().Where("age = 20").Find(&users)
// SELECT * FROM users WHERE age = 20;
物理删除
// Unscoped 方法可以物理删除记录
db.Unscoped().Delete(&order)
// DELETE FROM orders WHERE id=10;