使用 GORM实现增删改查操作| 青训营
介绍
中文官方网站内含十分齐全的中文文档。
关于包的说明
gorm.io/gorm 包和 github.com/jinzhu/gorm 包是 GORM 这个 ORM(对象关系映射)库的不同版本。
gorm.io/gorm:这是 GORM 的新版本,也称为 GORM v2。它是重写和改进后的版本,采用了更现代化的架构,提供了更强大和灵活的功能。它支持多种数据库驱动程序,并提供了更好的性能和扩展性。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"
gorm.io/driver/mysql: 这是 GORM v2 版本中用于 MySQL 数据库的驱动程序包。它是与 GORM v2.x.x 版本一起发布的,是 GORM 官方推荐的 MySQL 驱动。github.com/go-sql-driver/mysql: 这是 GORM v1 版本中用于 MySQL 数据库的驱动程序包。它是 GORM v1.x.x 版本的默认 MySQL 驱动,也是许多旧版本应用程序中使用的驱动。github.com/jinzhu/gorm/dialects/mysql: 这是 GORM v1 版本中提供的另一个 MySQL 驱动程序包。它是 GORM v1.x.x 版本中的备用 MySQL 驱动,与github.com/go-sql-driver/mysql有一些区别。github.com/jinzhu/gorm/dialects/postgres: 这个包是用于支持 PostgreSQL 数据库的驱动程序包,适用于 GORM v1 和 GORM v2 版本。github.com/jinzhu/gorm/dialects/sqlite: 这个包是用于支持 SQLite 数据库的驱动程序包,适用于 GORM v1 和 GORM v2 版本。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 还提供了一些其他功能和特性,用于帮助开发者更方便地与数据库进行交互。
- 数据迁移(Migration):GORM 支持数据库结构的自动迁移,可以根据定义的 Go 结构体自动生成数据库表或修改已存在的表结构。
- 高级查询:GORM 提供了强大的查询语法和方法,可以进行复杂的查询操作,包括条件查询、模糊查询、排序、分页等。
- 关联查询:GORM 支持在查询中进行关联查询,例如一对一、一对多、多对多等关系的查询。
- 事务操作:GORM 提供了事务管理的功能,可以确保一组数据库操作要么都成功,要么都失败。
- 预加载(Preloading):GORM 允许预加载关联的数据,减少数据库查询次数,提高查询性能。
- 软删除(Soft Delete):GORM 支持软删除,即在删除记录时,只修改标记字段而非实际删除数据,使其能够恢复或进行审计。
- 自动时间戳(Auto Timestamp):GORM 可以自动为模型添加创建时间和更新时间字段,并在创建和更新记录时进行自动填充。
- 钩子函数(Hooks):GORM 提供了多个钩子函数,可以在模型的不同生命周期阶段执行特定的代码逻辑。
- 数据库连接和连接池配置:GORM 允许配置数据库连接和连接池的参数,以满足不同的应用需求。
- 支持多种数据库:GORM 不仅支持 MySQL,还支持其他常见的数据库,如 PostgreSQL、SQLite、SQL Server 等。
这些功能和特性使得 GORM 成为一个强大且灵活的 ORM 框架,可以帮助开发者以更高效和便捷的方式进行数据库操作和管理。