Go框架三件套(Web/RPC/GORM)一 | 青训营
1.前言
1.1 Gorm
ORM(Object Relational Mapping, 对象关系映射),主要作用是在编程中,把面向对象的概念和数据库中表的概念对应起来;Gorm是一个已经迭代了10年+的功能强大的ORM框架,在字节内部被广泛使用并且拥有非常丰富的开源扩展。
1.2 Kitex
Kitex是字节内部的Golang微服务RPC框架,具有高性能、强可扩展的主要特点,支持多协议并且拥有丰富的开源扩展。
1.3 Hertz
Hertz是字节内部分HTTP框架,参考了其他开源框架的优势,结合字节跳动内部的需求,具有高易用性、高性能、高扩展性特点
2.GROM
2.1 GROM特性
- 全功能 ORM
- 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
- Create,Save,Update,Delete,Find 中钩子方法
- 支持
Preload、Joins 的预加载
- 事务,嵌套事务,Save Point,Rollback To Saved Point
- Context、预编译模式、DryRun 模式
- 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
- SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
- 复合主键,索引,约束
- Auto Migration
- 自定义 Logger
- 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
- 每个特性都经过了测试的重重考验
- 开发者友好
2.2 驱动方式链接
GORM 是通过驱动的方式来连接数据库的,目前支持 Mysql、SQLSever、PostgreSQL、SQLite。如果需要连接其他类型的数据库,可以 复用/自行 开发驱动。
- 驱动,是指软件驱动程序。是一种中间件,它能够将应用程序与硬件或其他系统之间的信息进行转换。在数据库领域中,驱动程序就是一种软件,它能够将应用程序与数据库之间的信息进行转换。
- 驱动程序通常提供一组标准的数据库连接接口。这些接口包括连接数据库、执行 SQL 语句、获取结果集等。应用程序可以使用这些接口与数据库进行交互。
在 GORM 中,驱动程序是将 Go 语言与数据库之间的信息进行转换的软件。 GORM 库使用驱动程序来连接数据库,并使用驱动程序提供的接口来进行数据库操作。这样,GORM 库就不用关心数据库是哪种数据库,只要有驱动程序就可以连接数据库。驱动是一种软件,它能够将 Go 语言与数据库之间的信息进行转换。驱动通过一组标准的数据库连接接口来提供连接数据库的功能。
GORM 的设计原则是对数据库访问进行封装,而不是对 SQL 语句进行封装。这样可以让开发人员专注于业务逻辑,而不用关心数据库的细节。以驱动的方式链接数据库的好处是:
- 使用驱动可以支持多种数据库,而不用对 GORM 进行修改。
- 使用驱动可以更好地支持数据库的新特性。
- 使用驱动可以更好地进行数据库性能优化。
2.3 DSN
DSN(Data Source Name)的缩写,是一种数据库连接字符串,它提供了连接数据库所需的所有信息,通常包括数据库类型、数据库名称、用户名、密码和连接地址等信息。例如对于 mysql 数据库来说,DSN 格式如user:password@tcp(host:port)/dbname
| 参数名 | 含义 |
|---|
| user | 数据库用户名 |
| password | 数据库密码 |
| host | 数据库地址 |
| port | 数据库端口 |
| dbname | 数据库名称 |
DSN 字符串的格式可能因数据库类型而异。使用DSN字符串连接数据库是一种常用的方式,因为它简化了连接数据库的过程,并且使用DSN字符串连接的数据库驱动程序通常支持多种数据库类型,这样就不用写多个连接数据库的函数了。
2.4 安装和简单实用
2.4.1 GORM安装
使用下面的命令进行安装
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
Quick Start
package main
import (
"gorm.io/gorm"
"gorm.io/driver/sqlite"
)
type Product struct {
gorm.Model
Code string
Price uint
}
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
db.AutoMigrate(&Product{})
db.Create(&Product{Code: "D42", Price: 100})
var product Product
db.First(&product, 1)
db.First(&product, "code = ?", "D42")
db.Model(&product).Update("Price", 200)
db.Model(&product).Updates(Product{Price: 200, Code: "F42"})
db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})
db.Delete(&product, 1)
}
2.4.2 Mysql 案例
案例说明
- 在 main 函数中,我们通过调用 gorm.Open("mysql", "root:password@/dbname?charset=utf8&parseTime=True&loc=Local") 来建立数据库连接。
- 我们使用 db.AutoMigrate(&Product{}) 来自动迁移数据库结构,即自动根据 Product 结构体创建数据表。
- 我们使用 db.Create(&Product{Name: "面包", Price: 3}) 来创建一条数据。
- 使用 db.Find(&products) 来查询所有数据并将其存入 products 变量中。
- 我们使用 db.Model(&Product{}).Where("name = ?", "面包").Update("price", 4) 来更新名称为 "面包" 的产品的价格。
- 我们使用 db.Where("name = ?", "面包").Delete(&Product{}) 来删除名称为 "面包" 的产品。
- 最后,通过 defer db.Close() 关闭数据库连接。
案例程序
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
type Product struct {
ID uint `gorm:"primary_key"`
Name string `gorm:"size:255"`
Price uint
}
func main() {
db, err := gorm.Open("mysql", "root:password@/dbname?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic("连接数据库失败")
}
defer db.Close()
db.AutoMigrate(&Product{})
db.Create(&Product{Name: "面包", Price: 3})
var products []Product
db.Find(&products)
fmt.Println("所有产品:", products)
db.Model(&Product{}).Where("name = ?", "面包").Update("price", 4)
db.Where("name = ?", "面包").Delete(&Product{})
}
可以使用gorm.Open()函数打开数据库连接db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
2.4.3 GORM用法
db.Create(&Product{Code: "L1212", Price: 1000})
var product Product
db.First(&product, 1)
db.Model(&product).Update("Price", 2000)
db.Delete(&product)
2.4.4 解决数据冲突
在 GORM 中,使用 OnConflict 方法可以解决数据冲突问题,指定在冲突时应该采取的操作。一般来说,在执行插入操作时可能会因为主键重复而导致数据冲突。使用 OnConflict 方法可以解决这个问题。db.Save(&Product{Name: "面包", Price: 3}).OnConflict("(name) DO UPDATE SET price = excluded.price").这行代码表示如果 name 列重复时,将执行更新操作来更新 price 列。还可以使用 OnConflict("(name) DO NOTHING") 来让重复的数据不做任何操作。
2.4.5 使用默认值
1) GORM 支持在数据库中设置默认值。这可以通过在结构体中使用 "default" 标签来实现。
type Product struct {
gorm.Model
Name string
Price int `gorm:"default:0"`
}
在创建或更新数据时,如果没有指定 Price 列的值,那么会自动将其设置为 0。
2) 默认值还可以使用SQL表达式和函数来进行设置。如果你想让 created_at 列默认值为当前时间,你可以这样定义:
type Product struct {
gorm.Model
Name string
Price int `gorm:"default:0"`
CreatedAt time.Time `gorm:"default:now()"`
}
设置默认值是非常有用的,它可以帮助你简化代码并减少错误。