GORM的学习笔记 | 青训营

77 阅读5分钟

GORM的学习笔记

GORM是开发Golang后端服务与关系型数据库交互的首选库,它几乎包含了你可能想到的所有跟数据库交互的功能,而且有非常完善且易懂的文档,以及庞大的社区。在使用过程中遇到任何问题,都可以很容易地获得解决方案。

这篇笔记文章会记录一下我初学GORM,实践基本的增删改查功能的过程。

数据库安装

这里多亏了1024code提供的数据库资源,可以很方便的在代码空间里绑定一个关系型数据库。并且数据库连接需要的信息都已经在环境变量中设置好了。

连接数据库

在我的Go项目中,我编辑了 main.go 文件:

package main

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
  "os"
)

func main() {
	dbUser := os.Getenv("MYSQL_USER")
	Pass := os.Getenv("MYSQL_PASSWORD")
	Host := os.Getenv("MYSQL_HOST")
	Port := os.Getenv("MYSQL_PORT")
  
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/mysql?charset=utf8mb4&parseTime=True&loc=Local", dbUser, Pass, Host, Port)
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("DB connection failed.")
	}
}

说明:

  1. 导入了相关的库。
  2. 在主函数中,首选通过os库从环境变量中获取数据库连接所需的信息,然后根据dsn的格式将这些信息插入,用这个dsn进行数据库连接
  3. 如果报错,我们就返回一个panic。否则,我们后面就可以用db来进行数据库交互了。

定义模型

因为刚好大项目也需要一个用户表单,我们就以此为例,定义一个User模型结构体:

type User struct {
  	ID          uint   `gorm:"primarykey"`
  	Username    string `gorm:"unique"`
  	Password    string
  }

其中,ID是主键。Username是用户名,设置为unique,也就是不能有重复的用户名。Password是密码,这里就简单的使用明文字符串。生产环境中我们应当使用更加复杂、安全的方式对用户的密码进行加密。

定义好模型之后,要记得将定义好的模型转换为数据库中的表单:

db.AutoMigrate(&User{})

现在我们来通过命令行连接一下MySQL数据库,验证一下表单有没有正确创建。

~/app$ mysql -h ${MYSQL_HOST} -P ${MYSQL_PORT} -u ${MYSQL_USER} -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1028
Server version: 8.0.30 MySQL Community Server - GPL

可以看到我们已经成功连上了MySQL数据库。

mysql> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> describe users;
+----------+-----------------+------+-----+---------+----------------+
| Field    | Type            | Null | Key | Default | Extra          |
+----------+-----------------+------+-----+---------+----------------+
| id       | bigint unsigned | NO   | PRI | NULL    | auto_increment |
| username | varchar(191)    | YES  | UNI | NULL    |                |
| password | longtext        | YES  |     | NULL    |                |
+----------+-----------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

可以看到现在数据库已经成功创建了名为mysql.users的表单(gorm会自动匹配MySQL的命名要求,用小写字母且复数单词)。其中的字段也是和我们的定义一一对应的。

实现增删改查

添加数据

我们添加一个名为Bob的用户,然后通过GORM在数据库中创建这条记录。

user := User{Username: "Bob", Password: "bobpassword"}
result := db.Create(&user)
if result.Error != nil {
	panic("Failed to insert data.")
}

在MySQL中验证一下结果:

mysql> select * from users;
+----+----------+-------------+
| id | username | password    |
+----+----------+-------------+
|  1 | Bob      | bobpassword |
+----+----------+-------------+
1 row in set (0.00 sec)

可以看到我们成功地创建了这条数据。

查找数据

我们先给数据库中多添加几条数据,然后用GORM对他们进行查询。

我们用上面的方法将下面的用户数据添加到了数据库中:

var users = []User{
	{Username: "Alice", Password: "alice123"},
	{Username: "Charlie", Password: "charlie456"},
	{Username: "David", Password: "david789"},
	{Username: "Eva", Password: "eva101112"},
	{Username: "Frank", Password: "frank131415"},
}

然后现在我对这些数据进行查询。这里我们尽可能的使用了多种不同的查询条件和方法。

  1. 按用户名查询:查询用户名为"Alice"的用户。

    var userAlice User
    db.Where("username = ?", "Alice").First(&userAlice)
    fmt.Println(userAlice)
    

    得到:

    {2 Alice alice123}
    
  2. 查询密码长度大于8的用户:这里我们使用SQL函数**LENGTH**。

    var usersWithLongPassword []User
    db.Where("LENGTH(password) > ?", 8).Find(&usersWithLongPassword)
    for _, user := range usersWithLongPassword {
        fmt.Println(user)
    }
    

    得到:

    {1 Bob bobpassword}
    {3 Charlie charlie456}
    {5 Eva eva101112}
    {6 Frank frank131415}
    
  3. 模糊查询:查询用户名中包含字母"a"的用户。

    var usersWithA []User
    db.Where("username LIKE ?", "%a%").Find(&usersWithA)
    for _, user := range usersWithA {
        fmt.Println(user)
    }
    

    得到:

    {2 Alice alice123}
    {3 Charlie charlie456}
    {4 David david789}
    {5 Eva eva101112}
    {6 Frank frank131415}
    
  4. 排序并取前两个:按用户名升序排序,取前两个用户。

    var firstTwoUsers []User
    db.Order("username ASC").Limit(2).Find(&firstTwoUsers)
    for _, user := range firstTwoUsers {
        fmt.Println(user)
    }
    

    得到:

    {2 Alice alice123}
    {1 Bob bobpassword}
    
  5. 偏移与限制:跳过第一个用户,取接下来的两个用户。

    var twoUsersAfterFirst []User
    db.Offset(1).Limit(2).Find(&twoUsersAfterFirst)
    for _, user := range twoUsersAfterFirst {
        fmt.Println(user)
    }
    

    得到:

    {2 Alice alice123}
    {3 Charlie charlie456}
    
  6. 统计查询:查询总用户数。

    var count int64
    db.Model(&User{}).Count(&count)
    fmt.Printf("Total number of users: %d\n", count)
    

    得到:

    Total number of users: 6
    

更新数据

这里我们尝试将用户Alice的密码修改掉:

userToUpdate := User{}
err := db.Where("username = ?", "Alice").First(&userToUpdate).Error
if err != nil {
    fmt.Println("Error finding user:", err)
    return
}
userToUpdate.Password = "AliceNewPassword"
db.Save(&userToUpdate)

可以看到在数据库中密码已经变成了AliceNewPassword

mysql> select * from users where username = "Alice";
+----+----------+------------------+
| id | username | password         |
+----+----------+------------------+
|  2 | Alice    | AliceNewPassword |
+----+----------+------------------+
1 row in set (0.00 sec)

删除数据

这里我尝试将密码长度小于10位的用户删除:

db.Where("LENGTH(password) < ?", 10).Delete(&User{})

可以看到用户David和Eva被删掉了:

mysql> select * from mysql.users;
+----+----------+------------------+
| id | username | password         |
+----+----------+------------------+
|  1 | Bob      | bobpassword      |
|  2 | Alice    | AliceNewPassword |
|  3 | Charlie  | charlie456       |
|  6 | Frank    | frank131415      |
+----+----------+------------------+
4 rows in set (0.00 sec)