GORM 是一个 Go 语言 ORM 库,它的目标是将数据库访问映射到 Go 语言中,构建一个友好的数据库访问层,对开发者隐藏底层的实现细节。本文主要记录了 GORM 连接MySQL数据库及CRUD的过程。
1. 依赖
使用 GORM 需要安装gorm.io/gorm和相应的数据库驱动,这里使用 MySQL,所以还需要安装gorm.io/driver/mysql。
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
2. 连接数据库
var db *gorm.DB
func InitDB() error {
dsn := "go-gorm-db:123456#QWErty@tcp(localhost:3306)/go-gorm-db?charset=utf8mb4&parseTime=True&loc=Local"
var err error
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
return err
}
return nil
}
预先创建一个名为go-gorm-db的数据库,然后创建专门用于连接数据库的用户go-gorm-db,并授予该用户对go-gorm-db数据库的合适权限,包括SELECT、INSERT、UPDATE、DELETE等。
程序开始时,调用InitDB()函数连接数据库,dsn是数据库连接字符串,其中包含了连接数据库的用户名、密码、地址、端口、数据库名等信息。
这样,就可以以go-gorm-db的用户身份连接到go-gorm-db数据库了。后续的CRUD操作都在db对象上进行。
3. 创建模型
使用 GORM 需要定义模型。模型是一个结构体,结构体的字段对应数据库表中的列。GORM 使用这个模型来处理数据库表中的数据。
type User struct {
ID uint `json:"id" gorm:"primary_key"`
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
Phone string `json:"phone"`
Age uint `json:"age"`
}
func (u *User) TableName() string {
return "user"
}
模型的定义中,使用标签gorm:"primary_key"标记了主键,使用标签json:"xxx"标记了字段在序列化时的名称。
TableName()方法返回模型对应的数据库表名,这里是user,如果没有定义该方法,GORM 会默认使用模型的结构体名称的复数形式作为表名。
4. 增删改查
这里使用gin框架创建一个简单的HTTP服务,对于每个增删改查操作,都定义一个相应的接口。
r := gin.Default()
// ...
r.Run(":8080")
4.1 Create
func (u *User) CreateUser(user User) error {
return db.Create(&user).Error
}
db.Create()方法用于创建一条记录,参数是一个指向模型的指针或模型的切片。这里使用&user传入指针。
接口: PUT /users
r.PUT("/users", func(c *gin.Context) {
var user controllers.User
if err := c.BindJSON(&user); err != nil {
// ...
}
if err := userHandler.CreateUser(user); err != nil {
// ...
}
c.JSON(200, gin.H{
"message": "success",
})
})
4.2 Read
func (u *User) GetUserByID(id uint) (User, error) {
var user User
err := db.Where("id = ?", id).Find(&user).Error
return user, err
}
db.Where()方法用于指定查询条件,db.Find()方法用于查询记录。这里使用&user传入指针。
查询条件可以是query字符串,也可以是结构体。使用结构体时,GORM只会将结构体中的非零值字段作为查询条件。
接口: GET /users/:id
r.GET("/users/:id", func(c *gin.Context) {
id := c.Param("id")
uid, err := strconv.Atoi(id)
if err != nil {
// ...
}
user, err := userHandler.GetUserByID(uint(uid))
if err != nil {
// ...
}
c.JSON(200, gin.H{
"data": user,
"message": "success",
})
})
4.3 Update
func (u *User) UpdateUser(id uint, user User) error {
user.ID = 0
return db.Model(&User{
ID: id,
}).Updates(user).Error
}
db.Model()方法用于指定模型,db.Updates()方法用于更新记录。这里使用&User{ID: id}传入指针。
接口: POST /users/:id
r.POST("/users/:id", func(c *gin.Context) {
id := c.Param("id")
uid, err := strconv.Atoi(id)
if err != nil {
// ...
}
var user controllers.User
if err := c.BindJSON(&user); err != nil {
// ...
}
if err := userHandler.UpdateUser(uint(uid), user); err != nil {
// ...
}
c.JSON(200, gin.H{
"data": user,
"message": "success",
})
})
4.4 Delete
func (u *User) DeleteUser(id uint) error {
return db.Delete(&User{}, id).Error
}
db.Delete()方法用于删除记录。这里指定删除&User{},并传入主键id。
如果模型中有DeletedAt字段,那么删除记录时,GORM会将该字段的值设置为当前时间,而不是真正地从数据库中删除记录,实现软删除。
接口: DELETE /users/:id
r.DELETE("/users/:id", func(c *gin.Context) {
id := c.Param("id")
uid, err := strconv.Atoi(id)
if err != nil {
// ...
}
if err := userHandler.DeleteUser(uint(uid)); err != nil {
// ...
}
c.JSON(200, gin.H{
"message": "success",
})
})
5. 总结与思考
后端的开发离不开增删改查这几个操作,无非是简单的CRUD和复杂的CRUD,GORM可以帮助我们完成这些操作,提高开发效率。
GORM 的使用较为简单,只需要定义模型,然后在模型上调用db.Create()、db.Find()、db.Updates()、db.Delete()等方法即可实现增删改查。
GORM 还提供了更多的功能,比如事务、连接池、钩子、预加载、分页、软删除等,可以根据实际需要进行使用。