使用 GORM实现增删改查操作| 青训营

124 阅读7分钟

使用 GORM实现增删改查操作| 青训营

介绍

Github GORM

中文官方网站内含十分齐全的中文文档。

关于包的说明

gorm.io/gorm 包和 github.com/jinzhu/gorm 包是 GORM 这个 ORM(对象关系映射)库的不同版本。

  1. gorm.io/gorm:这是 GORM 的新版本,也称为 GORM v2。它是重写和改进后的版本,采用了更现代化的架构,提供了更强大和灵活的功能。它支持多种数据库驱动程序,并提供了更好的性能和扩展性。
  2. github.com/jinzhu/gorm:这是 GORM 的旧版本,也称为 GORM v1。它是 GORM 最初发布的版本,在一段时间内非常流行。然而,随着时间的推移,它的开发逐渐停滞,不再推荐使用。

相比较而言`gorm.io/gorm版本具有以下优点:

  • 更好的性能和扩展性
  • 更干净、更简洁的代码结构
  • 更多的功能和选项
  • 更好的对多种数据库的支持
go get -u gorm.io/gorm

关于数据库驱动

连接不同的数据库都需要导入对应数据的驱动程序,GORM已经贴心的为我们包装了一些驱动程序,只需要按如下方式导入需要的数据库驱动即可:

import ("gorm.io/driver/mysql")
//"github.com/go-sql-driver/mysql"
//"github.com/jinzhu/gorm/dialects/mysql"
// import _ "github.com/jinzhu/gorm/dialects/postgres"
// import _ "github.com/jinzhu/gorm/dialects/sqlite"
// import _ "github.com/jinzhu/gorm/dialects/mssql"
  1. gorm.io/driver/mysql: 这是 GORM v2 版本中用于 MySQL 数据库的驱动程序包。它是与 GORM v2.x.x 版本一起发布的,是 GORM 官方推荐的 MySQL 驱动。
  2. github.com/go-sql-driver/mysql: 这是 GORM v1 版本中用于 MySQL 数据库的驱动程序包。它是 GORM v1.x.x 版本的默认 MySQL 驱动,也是许多旧版本应用程序中使用的驱动。
  3. github.com/jinzhu/gorm/dialects/mysql: 这是 GORM v1 版本中提供的另一个 MySQL 驱动程序包。它是 GORM v1.x.x 版本中的备用 MySQL 驱动,与 github.com/go-sql-driver/mysql 有一些区别。
  4. github.com/jinzhu/gorm/dialects/postgres: 这个包是用于支持 PostgreSQL 数据库的驱动程序包,适用于 GORM v1 和 GORM v2 版本。
  5. github.com/jinzhu/gorm/dialects/sqlite: 这个包是用于支持 SQLite 数据库的驱动程序包,适用于 GORM v1 和 GORM v2 版本。
  6. github.com/jinzhu/gorm/dialects/mssql: 这个包是用于支持 Microsoft SQL Server 数据库的驱动程序包,适用于 GORM v1 和 GORM v2 版本。

整合GORM

1. config包下创建yml配置文件

mysql:
  url: user:password@(localhost:port)/dbname?charset=utf8mb4&parseTime=True&loc=Local

2. utils包下初始化配置

package utils
​
import (
    "fmt"
    "github.com/spf13/viper"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/logger"
    "log"
    "os"
    "time"
)
​
func InitConfig() {
​
    //设置配置文件的名称为 "app"
    viper.SetConfigName("app")
​
    //添加配置文件的路径为 "config"
    viper.AddConfigPath("config")
​
    //读取配置文件并将其加载到 viper 中。
    err := viper.ReadInConfig()
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println("_________", viper.Get("mysql"))
}
​
var DB *gorm.DB
​
func InitMysql() {
    //自定义日志模板打印sql语句
    newLogger := logger.New(
        log.New(os.Stdout, "\r\n", log.LstdFlags),
        logger.Config{
            SlowThreshold: time.Second,
            LogLevel:      logger.Info,
            Colorful:      true,
        },
    )
    DB, _ = gorm.Open(mysql.Open(viper.GetString("mysql.url")), &gorm.Config{Logger: newLogger})
    // 其他操作...
}
​

3.启动类执行初始化方法

package main
​
import (
    "github.com/Moonlight-Zhao/go-project-example/router"
    "github.com/Moonlight-Zhao/go-project-example/utils"
)
​
func main() {
    utils.InitConfig()
    utils.InitMysql()
    router := router.SetupRouter()
    // 启动服务器
    router.Run(":8080")
}
​

4.repository包下写方法

package repository
​
import (
    "github.com/Moonlight-Zhao/go-project-example/utils"
    "log"
    "sync"
)
​
type Topic struct {
    Id         int64  `json:"id"`
    Title      string `json:"title"`
    Content    string `json:"content"`
    CreateTime int64  `json:"create_time"`
}
​
type TopicDao struct {
}
​
var (
    topicDao  *TopicDao
    topicOnce sync.Once
)
​
func (Topic) TableName() string {
    return "topic"
}
​
func (*TopicDao) Insert(topic Topic) error {
    result := utils.DB.Create(&topic)
    if result.Error != nil {
        // 插入数据失败,处理错误情况
        log.Println("fail:", result.Error)
        return result.Error
    }
    Init()
    return nil
}
​
func (*TopicDao) findAllTopics() ([]Topic, error) {
    var topics []Topic
    result := utils.DB.Find(&topics)
    if result.Error != nil {
        return nil, result.Error
    }
    return topics, nil
}
​

增删改查

package main
​
import (
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)
​
type User struct {
    ID   uint
    Name string
    Age  uint
}
​
func main() {
    // 连接数据库
    dsn := "user:password@tcp(127.0.0.1:3306)/database_name?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        panic("Failed to connect to database")
    }
​
    // 自动迁移模式,创建表结构
    db.AutoMigrate(&User{})
​
    // 创建用户
    user := User{Name: "Alice", Age: 25}
    db.Create(&user)
​
    // 查询用户
    var result User
    db.First(&result, user.ID)
    fmt.Printf("ID: %d, Name: %s, Age: %d\n", result.ID, result.Name, result.Age)
​
    // 方法二:链式调用 Where 方法
    var users []User
    db.Where("name = ?", "Alice").Where("age > ?", 25).Find(&users)
    
    // 更新用户
    db.Model(&result).Update("Age", 30)
​
    // 删除用户
    db.Delete(&result)
}
​

遇到的问题

Error 1146: Table 'go.posts' doesn't exist

代码指定了db.Table("post").AutoMigrate(&Post{})但是仍然报错

在 GORM 中,默认的表名规则为将结构体名转为复数形式作为表名(例如,Post 结构体对应的默认表名为 'posts')。

为了解决这个问题,你可以在定义 Post 结构体时使用 gorm:"table:post" 标签来指定表名,如下所示:

type Post struct {
    Id         int64  `gorm:"column:id" json:"id"`
    ParentId   int64  `gorm:"column:parent_id" json:"parent_id"`
    Content    string `gorm:"column:content" json:"content"`
    CreateTime int64  `gorm:"column:create_time" json:"create_time"`
}
​
// 指定表名为 "post"
func (Post) TableName() string {
    return "post"
}

通过在结构体中定义 TableName 方法,并返回 "post",就可以确保在执行 db.Create(&u1) 时访问的是名为 "post" 的表。

自增 id 值

如果数据库中的 id 字段是主键(Primary Key)、自增、非空和唯一的,那么在使用 GORM 创建一个新的 Post 记录时,你不需要手动指定 id 字段的值。数据库会自动生成并插入唯一的自增值。

在使用 db.Create(&u1) 前,你可以将 u1 结构体中的 id 字段设置为零值(例如,0 或 nil)

当调用 db.Create(&u1) 时,GORM 将会向数据库插入一条记录,并自动生成一个唯一的自增 id 值。

数据库权限

数据库权限问题,在mysql数据库中,user表存储了关于用户账户的信息。该表记录了允许访问数据库服务器的用户及其相关权限。

user表中常用的字段如下:

  • Host:表示允许连接到MySQL服务器的主机名或IP地址。使用%表示允许来自任何主机的连接。
  • User:表示用户账户的名称。
  • Password:存储经过加密的用户密码,用于验证用户身份。
  • Select_priv:表示用户是否具有选择数据的权限。
  • Insert_priv:表示用户是否具有插入数据的权限。
  • Update_priv:表示用户是否具有更新数据的权限。
  • Delete_priv:表示用户是否具有删除数据的权限。
  • Create_priv:表示用户是否具有创建新表和数据库的权限。
  • Drop_priv:表示用户是否具有删除表和数据库的权限。
  • Grant_priv:表示用户是否具有授予其他用户权限的权限。
  • Reload_priv:表示用户是否具有重新加载服务器配置的权限。
  • Shutdown_priv:表示用户是否具有关闭服务器的权限。
  • All_priv:表示用户是否具有所有权限,即对数据库的所有操作都具有权限。

权限字段的值可以是Y(表示具有相应权限)或者N(表示没有相应权限)。

其他功能和特性

GORM 还提供了一些其他功能和特性,用于帮助开发者更方便地与数据库进行交互。

  1. 数据迁移(Migration):GORM 支持数据库结构的自动迁移,可以根据定义的 Go 结构体自动生成数据库表或修改已存在的表结构。
  2. 高级查询:GORM 提供了强大的查询语法和方法,可以进行复杂的查询操作,包括条件查询、模糊查询、排序、分页等。
  3. 关联查询:GORM 支持在查询中进行关联查询,例如一对一、一对多、多对多等关系的查询。
  4. 事务操作:GORM 提供了事务管理的功能,可以确保一组数据库操作要么都成功,要么都失败。
  5. 预加载(Preloading):GORM 允许预加载关联的数据,减少数据库查询次数,提高查询性能。
  6. 软删除(Soft Delete):GORM 支持软删除,即在删除记录时,只修改标记字段而非实际删除数据,使其能够恢复或进行审计。
  7. 自动时间戳(Auto Timestamp):GORM 可以自动为模型添加创建时间和更新时间字段,并在创建和更新记录时进行自动填充。
  8. 钩子函数(Hooks):GORM 提供了多个钩子函数,可以在模型的不同生命周期阶段执行特定的代码逻辑。
  9. 数据库连接和连接池配置:GORM 允许配置数据库连接和连接池的参数,以满足不同的应用需求。
  10. 支持多种数据库:GORM 不仅支持 MySQL,还支持其他常见的数据库,如 PostgreSQL、SQLite、SQL Server 等。

这些功能和特性使得 GORM 成为一个强大且灵活的 ORM 框架,可以帮助开发者以更高效和便捷的方式进行数据库操作和管理。