grom官方网站
安装grom和mysql驱动
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
测试链接
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
})
if err != nil {
fmt.Printf("err: %v\n", err)
}
fmt.Printf("db: %v\n", db)
}
输出结果表示运行成功
db: &{0xc000116510 <nil> 0 0xc0001c6380 1}
GORM模型定义
GORM 定义一个 gorm.Model 结构体,其包括字段 ID、CreatedAt、UpdatedAt、DeletedAt
// gorm.Model 的定义
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
创建模型,根据模型生成数据库表
type User struct {
gorm.Model //内嵌gorm.Model
Name string
Age sql.NullInt64 //零值类型
Birthday *time.Time
Email string `gorm:"type:varchar(100);unique_index"`
Role string `gorm:"size:255"` //设置字段大小为255
MemberNumber *string `gorm:"unique;not null"` //设置会员号,唯一并且不为空
Num int `gorm:"AUTO_INCREMENT"` //设置num为自增类型
Address string `gorm:"index:addr"` //给address字段创建名为addr的索引
IgnoreMe int `gorm:"-"` //忽略本字段
}
func main() {
dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
})
if err != nil {
fmt.Printf("err: %v\n", err)
}
db.AutoMigrate(&User{
})
}
结构体中属性名的大驼峰对应数据库中下划线分割的字段
结构体的名字的复数对应数据库名字
+---------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-----------------+------+-----+---------+----------------+
| id | bigint unsigned | NO | PRI | NULL | auto_increment |
| created_at | datetime(3) | YES | | NULL | |
| updated_at | datetime(3) | YES | | NULL | |
| deleted_at | datetime(3) | YES | MUL | NULL | |
| name | longtext | YES | | NULL | |
| age | bigint | YES | | NULL | |
| birthday | datetime(3) | YES | | NULL | |
| email | varchar(100) | YES | | NULL | |
| role | varchar(255) | YES | | NULL | |
| member_number | varchar(191) | NO | UNI | NULL | |
| num | bigint | YES | | NULL | |
| address | varchar(191) | YES | MUL | NULL | |
+---------------+-----------------+------+-----+---------+----------------+
指定表明
func (User)TableName() string{
return "user_table"
}
创建表 插入数据
type User struct {
ID int64
Name string
Age int64
}
func main() {
dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
})
if err != nil {
fmt.Printf("err: %v\n", err)
}
//2,把模型与数据库中的表对应起来
db.AutoMigrate(&User{
})
//3,创建记录
user := User{
Name: "poole", Age: 23}
db.Create(&user)
}
通过tag设置字段,当该属性为空的时候,将值赋为默认值
type User struct {
ID int64
Name string
Age int64 `gorm:"default:20"`
}
注意:对于所有字段的零值,包括0
,""
,nil
都不会保存到数据库,使用的是他们的默认值,使用指针将避免此情况
type User struct {
ID int64
Name string
Age int64 `gorm:"default:20"`
}
结构体中传入的是一个空的指针,然后将在数据表中写入0值
user := User{
Name: "poole", Age: new(int64)}
db.Create(&user)
查询
检索单个对象
GORM 提供了First
、Take
、Last
方法,以便从数据库中检索单个对象。 当查询数据库时它添加了LIMIT 1
条件,且没有找到记录时,它会返回 错误ErrRecordNotFound
//获取第一条数据,主键升序
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;
result := db.First(&user)
result.RowsAffected // 返回找到的记录数
result.Error // returns error or nil
根据主键检索
db.First(&user, 3)
// SELECT * FROM users WHERE id = 3;
db.First(&user, "10")
// SELECT * FROM users WHERE id = 10;
db.Find(&users, []int{
1,2,3})
// SELECT * FROM users WHERE id IN (1,2,3);
对于传入的主键ID
数据,将它放入User
中,直接传递给First
user := User{
ID: 2}
db.First(&user)
查询多个对象
查询全部对象:
db.Find(&users)
// SELECT * FROM users;
条件查询
string条件
获取第一个匹配的记录
db.Where("name=?", "green").First(&user)
//SELECT * FROM users WHERE name = 'green' ORDER BY id LIMIT 1;
获取所有匹配的记录,所有不等于poole的数据
db.Where("name <> ?", "poole").Find(&users)
//SELECT * FROM users WHERE name <> 'poole';
IN
db.Where("name IN ?", []string{
"green", "poole"}).Find(&users)
// SELECT * FROM users WHERE name IN ('green','poole');
LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)
// SELECT * FROM users WHERE name LIKE '%jin%';
AND
db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;
struct & map 条件
struct
db.Where(&User{
Name: "poole", Age: 23}).First(&user)
//SELECT * FROM users WHERE name = "poole" AND age = 23 ORDER BY id LIMIT 1;
map
db.Where(map[string]interface{
}{
"name": "poole", "age": 23}).Find(&users)
// SELECT * FROM users WHERE name = "poole" AND age = 23;
slice:切片中数据的主键查询
db.Where([]int64{
2, 3, 5}).Find(&users)
// SELECT * FROM users WHERE id IN (2, 3, 5);
需要注意的是,查询条件有零元素的时候,需要使用map的形式,而不是struct的形式
//struct
db.Where(&User{
Name: "poole", Age: 0}).Find(&users)
// SELECT * FROM users WHERE name = "poole";
//map
db.Where(map[string]interface{
}{
"Name": "poole", "Age": 0}).Find(&users)
// SELECT * FROM users WHERE name = "poole" AND age = 0;
内联条件
查询条件可以内联到First
和Find
等方法中,其方式与 Where
类似。
//二者是等价的
db.Where("id=?", 2).First(&user)
db.First(&user, "id=?", 2)
Not条件
db.Not("name=?", "looney").Find(&users)
//select * from users where not name ="looney" order by id;
Or条件
db.Where("name=?", "looney").Or("name=?", "poole").Find(&users)
//select * from users where name ="looney" or name ="poole";
选择特定字段
db.Select("name", "age").Find(&users)
//select name,age from users;
排序
db.Order("age desc, name").Find(&users)
//select * from users order by age desc,name;
db.Order("age desc").Order("name").Find(&users)
//select * from users order by age desc,name;
Limit & Offset
db.Limit(3).Find(&users)
//select * from users limit 3;
db.Limit(2).Offset(1).Find(&users)
//select * from users limit 2 offset 1;
高级查询
智能选取字段
GORM 允许通过 Select 方法选择特定的字段,如果您在应用程序中经常使用此功能,你也可以定义一个较小的结构体,以实现调用 API 时自动选择特定的字段,例如:
type User struct {
ID int64
Name string
Age int64
}
type ApiUser struct {
ID int64
Name string
}
users := []ApiUser{
}
db.Model(&User{
}).Limit(3).Find(&users)
fmt.Printf("%v\n", users)
//select id,name from users limit 3;
//[{1 poole} {2 looney} {3 green}]
子查询
子查询可以嵌套在查询中,GORM 允许在使用 *gorm.DB 对象作为参数时生成子查询
db.Where("amount > (?)", db.Table("orders").Select("AVG(amount)")).Find(&orders)
//SELECT * FROM "orders" WHERE amount > (SELECT AVG(amount) FROM "orders");
更新
保存所有字段
Save
会保存所有的字段,即使字段是零值
user := User{
}
db.First(&user)
user.Name = "poole"
db.Save(&user)
更新单列
使用Update
更新单列时,需要有一些条件,否则将会引起错误 ErrMissingWhereClause
//条件更新
db.Model(&User{
}).Where("id=?", 2).Update("age", 26)
//update users set age =26 where id =2;
//根据user的值进行更新
user := User{
ID: 2}
db.Model(&user).Update("name", "Kevin Rooney")
//update users set name="Kevin Rooney" where id =2;
//根据条件和user的值进行更新
db.Model(&user).Where("age=?", 26).Update("name", "looney")
//update users set name="looney" where id =2 and age =26;
更新多列
Updates
方法支持struct
和map[string]interface{}
参数
//根据 struct 更新属性,只会更新非零值的字段
user := User{
ID: 3}
db.Model(&user).Updates(User{
Name: "Kevin", Age: 27})
//update users set name ="Kevin",age =27 where id =3;
//根据map更新属性
db.Model(&user).Updates(map[string]interface{
}{
"name": "green", "age": 32})
//update users set name ="green",age =32 where id =3;
更新选定字段
如果您想要在更新时选定、忽略某些字段,您可以使用 Select
、Omit
//选定某些字段
db.Model(&user).Select("age").Updates(User{
Name: "green", Age: 27})
//update users set age =27 where id = 3;
//忽略某些字段
db.Model(&user).Omit("name").Updates(User{
Name: "green", Age: 27})
//update users set age =27 where id = 3;
批量更新
db.Model(User{
}).Where("age=?", 23).Updates(User{
Name: "super start"})
//update users set name = "super start" where age = 23;
阻止全局更新
如果在没有任何条件的情况下执行批量更新,默认情况下,GORM 不会执行该操作,并返回ErrMissingWhereClause
错误
db.Model(&User{
}).Update("name", "poole").Error // gorm.ErrMissingWhereClause
db.Model(&User{
}).Where("1 = 1").Update("name", "poole")
// UPDATE users SET `name` = "poole" WHERE 1=1
db.Exec("UPDATE users SET name = ?", "poole")
// UPDATE users SET name = "poole"
db.Session(&gorm.Session{
AllowGlobalUpdate: true}).Model(&User{
}).Update("name", "poole")
// UPDATE users SET `name` = "poole"
更新记录数量
tx := db.Model(User{
}).Where("age=?", 23).Updates(User{
Name: "mvp"})
fmt.Printf("%v\n", tx.RowsAffected)
使用sql表达式更新
db.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100))
// UPDATE "products" SET "price" = price * 2 + 100 WHERE "id" = 3;
删除
删除一条记录
删除一条记录时,删除对象需要指定主键,否则会触发批量delelte
user := User{
ID: 6}
db.Delete(&user)
//delete from users where id = 6;
//添加额外条件的删除
db.Where("name=?","green").Delete(&user)
//delete from users where id = 6 and name = "green"
根据主键删除
//主键可以使用数字或者字符串
db.Delete(&User{
}, 7)
//delete from users where id =7;
db.Delete(&User{
}, "7")
//delete from users where id =7;
db.Delete(&users, []int{
1,2,3})
//delete from users where id in (1,2,3);
批量删除
如果指定的值不是主键,那么gorm会执行批量删除,它将删除所有匹配的记录
db.Where("name like ?", "%zhang%").Delete(&User{
})
//delete from users where name like "%zhang%";
db.Delete(&User{
}, "email like ?", "%zhang%")
//deleye from users where name like "%zhang%"
阻止全局删除
如果在没有任何条件的情况下执行批量删除,GORM 不会执行该操作,并返回 ErrMissingWhereClause
错误
db.Delete(&User{
}).Error // gorm.ErrMissingWhereClause
db.Where("1 = 1").Delete(&User{
})
// delete from `users` where 1=1;
db.Exec("DELETE FROM users")
// delete from users;
db.Session(&gorm.Session{
AllowGlobalUpdate: true}).Delete(&User{
})
// delete from users;
软删除
如果您的模型包含了一个 gorm.deletedat
字段(gorm.Model
已经包含了该字段),它将自动获得软删除的能力!
user := User{
ID: 7}
db.Delete(&user)
// update users set deleted_at="1999-10-29 23:23" where id = 7;
//查询时会忽略被软删除的记录
db.Where("age=20").Find(&user)
//select * from users where age = 20 and delete_at is null;
查询被软删除的记录
可以使用Unscoped
找到被软删除的记录
db.Unscoped().Where("age = 20").Find(&users)
// select * from users where age = 20;
永久删除
使用Unscoped
永久删除匹配的记录
db.Unscoped().Delete(&user)
// delete from users where id=10;