1.模型使用
约定:GORM 倾向于约定,而不是配置。默认情况下,GORM 使用 ID 作为主键,使用结构体名的 蛇形复数 作为表名,字段名的 蛇形 作为列名,并使用 CreatedAt、UpdatedAt 字段追踪创建、更新时间
GORM 定义一个 gorm.Model 结构体,其包括字段 ID、CreatedAt、UpdatedAt、DeletedAt
type Model struct { ID uint `gorm:"primarykey"` CreatedAt time.Time UpdatedAt time.Time DeletedAt DeletedAt `gorm:"index"` }
建表实例:
package main import ( "gorm.io/driver/mysql" "gorm.io/gorm" ) // 数据表 type UserInfo struct { ID int64 Name string Hobby string } func main() { dsn := "root:root@tcp(127.0.0.1:3306)/gorm_test?charset=utf8mb4&parseTime=True&loc=Local" db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) db.AutoMigrate(&UserInfo{}) // 生成表结构 }
2.创建表记录
普通的创建:
package main import ( "fmt" "gorm.io/driver/mysql" "gorm.io/gorm" ) // 数据表 type UserInfo struct { ID int64 Name string Hobby string } func main() { dsn := "root:root@tcp(127.0.0.1:3306)/gorm_test?charset=utf8mb4&parseTime=True&loc=Local" db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) userInfo := UserInfo{Name: "dahe", Hobby: "Go语言"} result := db.Create(&userInfo) fmt.Println(result.RowsAffected) // 返回插入记录的条数 if result.Error == nil { // 检测error fmt.Println("no errors!!!") } }
批量插入:
要有效地插入大量记录,请将一个 slice 传递给 Create 方法。 GORM 将生成单独一条SQL语句来插入所有数据,并回填主键的值,钩子方法也会被调用。
package main import ( "fmt" "gorm.io/driver/mysql" "gorm.io/gorm" ) // 数据表 type UserInfo struct { ID int64 Name string Hobby string } func main() { dsn := "root:root@tcp(127.0.0.1:3306)/gorm_test?charset=utf8mb4&parseTime=True&loc=Local" db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) var userInfo = []UserInfo{{Name: "qianyue"}, {Name: "王伟"}, {Name: "李四"}} result := db.Create(&userInfo) fmt.Println(result.RowsAffected) // 返回插入记录的条数 if result.Error == nil { // 检测error fmt.Println("no errors!!!") } }
使用 CreateInBatches
分批创建时,你可以指定每批的数量,例如:
// 数量为 100 db.CreateInBatches(users, 100)
3.查询记录
检索单个对象
GORM 提供了 First、Take、Last 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件,且没有找到记录时,它会返回 ErrRecordNotFound 错误
package main import ( "fmt" "gorm.io/driver/mysql" "gorm.io/gorm" ) // 数据表 type UserInfo struct { ID int64 Name string Hobby string } func main() { dsn := "root:root@tcp(127.0.0.1:3306)/gorm_test?charset=utf8mb4&parseTime=True&loc=Local" db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) var userInfo UserInfo result := db.First(&userInfo) // 查询表的第一行 fmt.Println(userInfo) // 输出查询的结果 fmt.Println(result.RowsAffected) // 返回插入记录的条数 if result.Error == nil { // 检测error fmt.Println("no errors!!!") } }
// 获取第一条记录(主键升序) 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 // 检查 ErrRecordNotFound 错误 errors.Is(result.Error, gorm.ErrRecordNotFound)
First 和 Last 会根据主键排序,分别查询第一条和最后一条记录。 只有在目标 struct 是指针或者通过db.Model() 指定 model 时,该方法才有效。 此外,如果相关 model 没有定义主键,那么将按 model的第一个字段进行排序。
用主键检索
如果主键是数字类型,您可以使用 内联条件 来检索对象。 传入字符串参数时,需要特别注意 SQL 注入问题
db.First(&user, 10) // SELECT * FROM users WHERE id = 10; 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);
如果主键是字符串(例如像 uuid),查询将被写成这样:
db.First(&user, "id = ?", "1b74413f-f3b8-409f-ac47-e8c062e3472a") // SELECT * FROM users WHERE id = "1b74413f-f3b8-409f-ac47-e8c062e3472a";
检索全部对象
// Get all records result := db.Find(&users) // SELECT * FROM users; result.RowsAffected // returns found records count, equals `len(users)` result.Error // returns error
条件
string条件:
// Get first matched record db.Where("name = ?", "jinzhu").First(&user) // SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1; // Get all matched records db.Where("name <> ?", "jinzhu").Find(&users) // SELECT * FROM users WHERE name <> 'jinzhu'; // IN db.Where("name IN ?", []string{"jinzhu", "jinzhu 2"}).Find(&users) // SELECT * FROM users WHERE name IN ('jinzhu','jinzhu 2'); // 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; // Time db.Where("updated_at > ?", lastWeek).Find(&users) // SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00'; // BETWEEN db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users) // SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';
内联条件:
// 如果是非整数类型,则通过主键获取 db.First(&user, "id = ?" , "string_primary_key" ) // SELECT * FROM users WHERE id = 'string_primary_key'; // 普通 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; // Map db.Find(&users, map [ string ] interface {}{ "age" : 20 }) // SELECT * FROM users WHERE age = 20;
Not 条件:
构建 NOT 条件,工作方式类似于Where
db.Not( "name = ?" , "jinzhu" ).First(&user) // SELECT * FROM users WHERE NOT name = "jinzhu" ORDER BY id LIMIT 1; // 不在 db.Not( map [ string ] interface {}{ "name" : [] string { "jinzhu" , "jinzhu 2" }}).Find(&users) // SELECT * FROM users WHERE name NOT IN (“金珠”、“金珠2”); // Struct db.Not(User{Name: "jinzhu" , Age: 18 }).First(&user) // SELECT * FROM users WHERE name <> "jinzhu" AND age <> 18 ORDER BY id LIMIT 1; // 不在主键切片中 db.Not([] int64 { 1 , 2 , 3 }).First(&user) // SELECT * FROM users WHERE id NOT IN (1,2,3) ORDER BY id LIMIT 1 ;
Or 条件:
db.Where( "role = ?" , "admin" ) .Or( "role = ?" , "super_admin" ).Find(&users) // SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin' ; // Struct db.Where( "name = 'jinzhu'" ).Or(User{Name: "jinzhu 2" , Age: 18 }).Find(&users) // SELECT * FROM users WHERE name = 'jinzhu' OR (姓名 = '金珠 2' AND 年龄 = 18); // Map db.Where( "name = 'jinzhu'" ).Or( map [ string ] interface {}{ "name" : "jinzhu 2" , "age" : 18 }).Find(&users) // SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);
限制和偏移
Limit指定要检索的最大记录数Offset指定在开始返回记录之前要跳过的记录数
db.Limit( 3 ).Find(&users) // SELECT * FROM users LIMIT 3; // 使用 -1 取消限制条件 db.Limit( 10 ).Find(&users1).Limit( -1 ).Find(&users2) // SELECT * FROM users LIMIT 10; (users1) // 选择 * FROM 用户;(用户2) db.Offset( 3 ).Find(&users) // SELECT * FROM users OFFSET 3; db.Limit( 10 ).Offset( 5 ).Find(&users) // SELECT * FROM users OFFSET 5 LIMIT 10; // 使用 -1 取消偏移条件 db.Offset( 10 ).Find(&users1).Offset( -1 ).Find(&users2) // SELECT * FROM users OFFSET 10; (users1) // 选择 * FROM 用户;(用户2)
4.更新
简要更新
package main import ( "gorm.io/driver/mysql" "gorm.io/gorm" ) // 数据表 type UserInfo struct { ID int64 Name string Hobby string } func main() { dsn := "root:root@tcp(127.0.0.1:3306)/gorm_test?charset=utf8mb4&parseTime=True&loc=Local" db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) var userInfo UserInfo db.First(&userInfo) userInfo.Hobby = "Java" userInfo.Name = "dahezhiquan" db.Save(&userInfo) }
更新单个列
当使用 Update 更新单个列时,你需要指定条件,否则会返回 ErrMissingWhereClause 错误
package main import ( "gorm.io/driver/mysql" "gorm.io/gorm" ) // 数据表 type UserInfo struct { ID int64 Name string Hobby string } func main() { dsn := "root:root@tcp(127.0.0.1:3306)/gorm_test?charset=utf8mb4&parseTime=True&loc=Local" db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) // var userInfo UserInfo db.Model(&UserInfo{}).Where("id = ?", 1).Update("name", "gorm") }
// 条件更新 db.Model(&User{}).Where("active = ?", true).Update("name", "hello") // UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE active=true; // User 的 ID 是 `111` db.Model(&user).Update("name", "hello") // UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111; // 根据条件和 model 的值进行更新 db.Model(&user).Where("active = ?", true).Update("name", "hello") // UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;
5.删除
删除一条记录
删除一条记录时,删除对象需要指定主键,否则会触发 批量 Delete,例如:
// Email 的 ID 是 `10` db.Delete(&email) // DELETE from emails where id = 10; // 带额外条件的删除 db.Where("name = ?", "jinzhu").Delete(&email) // DELETE from emails where id = 10 AND name = "jinzhu";
根据主键删除
db.Delete(&User{}, 10) // DELETE FROM users WHERE id = 10; db.Delete(&User{}, "10") // DELETE FROM users WHERE id = 10; db.Delete(&users, []int{1,2,3}) // DELETE FROM users WHERE id IN (1,2,3);