这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
Gorm 的使用
gorm 是一个已经迭代了十多年的ORM框架,在字节跳动被广泛使用。
使用gorm连接mysql的案例
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
// refer https://github.com/go-sql-driver/mysql#dsn-data-source-name for details
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{})
}
为了正确处理time.Time,您需要包括parseTime作为参数。 为了完全支持UTF-8编码,需要将charset=utf8更改为charset=utf8mb4。 GORM使用database/sql 去维持连接池
sqlDB, err := db.DB() // SetMaxIdleConns sets the maximum number of connections in the idle connection pool.
sqlDB.SetMaxIdleConns(10) // SetMaxOpenConns sets the maximum number of open connections to the database.
sqlDB.SetMaxOpenConns(100) // SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
sqlDB.SetConnMaxLifetime(time.Hour)
创建
创建记录
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
result := db.Create(&user) // pass pointer of data to Create
user.ID // returns inserted data's primary key
result.Error // returns error
result.RowsAffected // returns inserted records count
选定区域创建记录
db.Select("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("jinzhu", 18, "2020-07-04 11:05:21.775")
非选定区域创建记录
db.Omit("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`birthday`,`updated_at`) VALUES ("2020-01-01 00:00:00.000", "2020-07-04 11:05:21.775")
查询
使用First查询时,当查询不到数据时,会返回ErrRecordNotFound,使用Find查询数据时,查询不到数据不会返回错误。当使用结构体查询数据时,GORM只会查询非0字段,这意味着,如果查询字段值为0,“”,false或者其他0值,该字段不会用于构建查询字段。建议使用map查询。
// Struct
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 ORDER BY id LIMIT 1;
// Map
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;
// Slice of primary keys
db.Where([]int64{20, 21, 22}).Find(&users)
// SELECT * FROM users WHERE id IN (20, 21, 22);
更新数据
使用struct更新时,只会更新非0值,如果需要更新非0值建议使用map更新
// Update attributes with `struct`, will only update non-zero fields
db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;
// Update attributes with `map`
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
// UPDATE users SET name='hello', age=18, actived=false, updated_at='2013-11-17 21:34:10' WHERE id=111;
删除数据
软删除
// user's ID is `111`
db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// Batch Delete
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
// Soft deleted records will be ignored when querying
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
如果你的模型包括一个gorm。DeletedAt字段(包含在gorm.Model中),它将自动获得软删除能力! 当调用Delete时,记录不会从数据库中删除,但是GORM会将DeletedAt的值设置为当前时间,并且数据不能再用普通的查询方法找到。
事务
GORM在事务内部执行写(创建/更新/删除)操作,以确保数据的一致性,如果不需要,可以在初始化时禁用它,在此之后您将获得约30%以上的性能提升
// Globally disable
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
SkipDefaultTransaction: true,
})
// Continuous session mode
tx := db.Session(&Session{SkipDefaultTransaction: true})
tx.First(&user, 1)
tx.Find(&users)
tx.Model(&user).Update("Age", 18)
GORM支持嵌套事务,你可以回滚在一个大事务范围内执行的操作的子集,例如:
DB.Transaction(func(tx *gorm.DB) error {
tx.Create(&user1)
tx.Transaction(func(tx2 *gorm.DB) error {
tx2.Create(&user2)
return errors.New("rollback user2") // Rollback user2
})
tx.Transaction(func(tx2 *gorm.DB) error {
tx2.Create(&user3)
return nil
})
return nil })
// Commit user1, user3
kitex 是字节跳动内部的golang微服务框架。 Hertz 是字节跳动内部的HTTP框架。