GORM框架
gorm地址 :https://github.com/go-gorm/gorm
目前使用最广泛的一个go语言数据库框架
1、入门
数据库以目前使用最多的mysql为例。
//安装MySQL驱动
go get -u gorm.io/driver/mysql
//安装gorm包
go get -u gorm.io/gorm
//安装gin
go get -u github.com/gin-gonic/gin
涉及到的数据库sql:
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`username` varchar(30) NOT NULL COMMENT '账号',
`password` varchar(100) NOT NULL COMMENT '密码',
`createtime` bigint(20) NOT NULL DEFAULT 0 COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
//定义User模型,绑定users表,ORM库操作数据库,需要定义一个struct类型和MYSQL表进行绑定或者叫映射,struct字段和MYSQL表字段一一对应
type User struct {
ID int64 // 主键
//通过在字段后面的标签说明,定义golang字段和表字段的关系
//例如 `gorm:"column:username"` 标签说明含义是: Mysql表的列名(字段名)为username
Username string `gorm:"column:username"`
Password string `gorm:"column:password"`
//创建时间,时间戳
CreateTime int64 `gorm:"column:createtime"`
}
package dao
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func init() {
//配置MySQL连接参数
username := "root" //账号
password := "root" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
Dbname := "gorm" //数据库名
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", username, password, host, port, Dbname)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
}
插入数据:
package dao
import "log"
type User struct {
ID int64
Username string `gorm:"column:username"`
Password string `gorm:"column:password"`
CreateTime int64 `gorm:"column:createtime"`
}
func (u User) TableName() string {
//绑定MYSQL表名为users
return "users"
}
func Save(user *User) {
err := DB.Create(user)
if err != nil {
log.Println("insert fail : ", err)
}
}
package api
import (
"github.com/gin-gonic/gin"
"test.com/gormtest/dao"
"time"
)
func SaveUser(c *gin.Context) {
user := &dao.User{
Username: "zhangsan",
Password: "123456",
CreateTime: time.Now().UnixMilli(),
}
dao.Save(user)
c.JSON(200, user)
}
package api
import "github.com/gin-gonic/gin"
func RegisterRouter(r *gin.Engine) {
r.GET("/save", SaveUser)
}
测试,数据成功保存,并获取到id
查询:
func GetById(id int64) User {
var user User
err := DB.Where("id=?", id).First(&user).Error
if err != nil {
log.Println("get user by id fail : ", err)
}
return user
}
func GetUser(c *gin.Context) {
user := dao.GetById(1)
c.JSON(200, user)
}
func GetAll() []User {
var users []User
err := DB.Find(&users)
if err != nil {
log.Println("get users fail : ", err)
}
return users
}
func GetUser(c *gin.Context) {
user := dao.GetAll()
c.JSON(200, user)
}
更新:
func UpdateById(id int64) {
err := DB.Model(&User{}).Where("id=?", id).Update("username", "lisi")
if err != nil {
log.Println("update users fail : ", err)
}
}
func UpdateUser(c *gin.Context) {
dao.UpdateById(1)
user := dao.GetById(1)
c.JSON(200, user)
}
删除:
func DeleteById(id int64) {
err := DB.Where("id=?", id).Delete(&User{})
if err != nil {
log.Println("delete users fail : ", err)
}
}
func DeleteUser(c *gin.Context) {
dao.DeleteById(1)
user := dao.GetById(1)
c.JSON(200, user)
}
2、模型定义
前面入门案例中,我们定义了User结构体用来和数据表users做映射,User结构体,我们称之为数据模型,在gorm框架中,操作数据库需要预先定义模型。
底层都是使用的golang的database标准库,利用反射原理,执行读写操作时,将结构体翻译为sql语句,并将结果转化为对应的模型。
2.1 模型定义
假设有一个商品表
CREATE TABLE `goods` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID,商品Id',
`name` varchar(30) NOT NULL COMMENT '商品名',
`price` decimal(10,2) unsigned NOT NULL COMMENT '商品价格',
`type_id` int(10) unsigned NOT NULL COMMENT '商品类型Id',
`createtime` int(10) NOT NULL DEFAULT 0 COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
将上述表翻译为模型后,如下:
type Good struct {
Id int //表字段名为:id
Name string //表字段名为:name
Price float64 //表字段名为:price
TypeId int //表字段名为:type_id
CreateTime int64 `gorm:"column:createtime"` //表字段名为:createtime
}
默认gorm对struct字段名使用Snake Case命名风格转换成mysql表字段名(需要转换成小写字母)。
Snake Case命名风格,就是各个单词之间用下划线(_)分隔,例如: CreateTime的Snake
Case风格命名为create_time
同时默认情况下,使用ID做为其主键,使用结构体名称的Snake Case风格的复数形式做为表名,使用 CreatedAt、UpdatedAt 字段追踪创建、更新时间。
2.2 模型标签
标签定义:
`gorm:"标签内容"`
标签定义部分,多个标签定义可以使用分号(;)分隔
gorm常用标签如下:
其他的可以查看官方文档:https://gorm.io/zh_CN/docs/models.html#embedded_struct
2.3. 表名映射
- 复数表名,比如结构体User,默认的表名为users
- 实现Tabler接口 (TableName 不支持动态变化,它会被缓存下来以便后续使用。)
type Tabler interface {
TableName() string
}
// TableName 会将 User 的表名重写为 `profiles`
func (User) TableName() string {
return "profiles"
}
- 动态表名,使用Scopes
func UserTable(user User) func (tx *gorm.DB) *gorm.DB {
return func (tx *gorm.DB) *gorm.DB {
if user.Admin {
return tx.Table("admin_users")
}
return tx.Table("users")
}
}
db.Scopes(UserTable(user)).Create(&user)
- 临时表名
db.Table("deleted_users")
2.4 Model
GORM 定义一个 gorm.Model 结构体,其包括字段 ID、CreatedAt、UpdatedAt、DeletedAt
// gorm.Model 的定义
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
GORM 约定使用 CreatedAt、UpdatedAt 追踪创建/更新时间。如果定义了这种字段,GORM 在创建、更新时会自动填充当前时间。
要使用不同名称的字段,您可以配置 autoCreateTime、autoUpdateTime 标签
如果想要保存 UNIX(毫/纳)秒时间戳,而不是 time,只需简单地将 time.Time 修改为 int 即可。
例子:
type User struct {
CreatedAt time.Time // 默认创建时间字段, 在创建时,如果该字段值为零值,则使用当前时间填充
UpdatedAt int // 默认更新时间字段, 在创建时该字段值为零值或者在更新时,使用当前时间戳秒数填充
Updated int64 `gorm:"autoUpdateTime:nano"` // 自定义字段, 使用时间戳填纳秒数充更新时间
Updated int64 `gorm:"autoUpdateTime:milli"` //自定义字段, 使用时间戳毫秒数填充更新时间
Created int64 `gorm:"autoCreateTime"` //自定义字段, 使用时间戳秒数填充创建时间
}
可以将它嵌入到您的结构体中,以包含这几个字段,比如
type User struct {
gorm.Model
Name string
}
// 等效于
type User struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
Name string
}
对于正常的结构体字段,你也可以通过标签 embedded 将其嵌入,例如:
type Author struct {
Name string
Email string
}
type Blog struct {
ID int
Author Author `gorm:"embedded"`
Upvotes int32
}
// 等效于
type Blog struct {
ID int64
Name string
Email string
Upvotes int32
}
可以使用标签 embeddedPrefix 来为 db 中的字段名添加前缀,例如:
type Blog struct {
ID int
Author Author `gorm:"embedded;embeddedPrefix:author_"`
Upvotes int32
}
// 等效于
type Blog struct {
ID int64
AuthorName string
AuthorEmail string
Upvotes int32
}
2.5 数据库连接
GORM 官方支持的数据库类型有: MySQL, PostgreSQL, SQlite, SQL Server
连接数据库主要是两个步骤:
- 配置DSN (Data Source Name)
- 使用gorm.Open连接数据库
2.5.1 DSN
gorm库使用dsn作为连接数据库的参数,dsn翻译过来就叫数据源名称,用来描述数据库连接信息。一般都包含数据库连接地址,账号,密码之类的信息。
格式:
[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN]
mysql的dsn的一些例子:
//mysql dsn格式
//涉及参数:
//username 数据库账号
//password 数据库密码
//host 数据库连接地址,可以是Ip或者域名
//port 数据库端口
//Dbname 数据库名
username:password@tcp(host:port)/Dbname?charset=utf8&parseTime=True&loc=Local
//填上参数后的例子
//username = root
//password = 123456
//host = localhost
//port = 3306
//Dbname = gorm
//后面K/V键值对参数含义为:
// charset=utf8 客户端字符集为utf8
// parseTime=true 支持把数据库datetime和date类型转换为golang的time.Time类型
// loc=Local 使用系统本地时区
root:123456@tcp(localhost:3306)/gorm?charset=utf8&parseTime=True&loc=Local
//gorm 设置mysql连接超时参数
//开发的时候经常需要设置数据库连接超时参数,gorm是通过dsn的timeout参数配置
//例如,设置10秒后连接超时,timeout=10s
//下面是完成的例子
root:123456@tcp(localhost:3306)/gorm?charset=utf8&parseTime=True&loc=Local&timeout=10s
//设置读写超时时间
// readTimeout - 读超时时间,0代表不限制
// writeTimeout - 写超时时间,0代表不限制
root:123456@tcp(localhost:3306)/gorm?charset=utf8&parseTime=True&loc=Local&timeout=10s&readTimeout=30s&writeTimeout=60s
要支持完整的 UTF-8 编码,您需要将 charset=utf8 更改为 charset=utf8mb4
2.5.2 连接数据库
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
}
MySQL 驱动程序提供了 一些高级配置 可以在初始化过程中使用,例如:
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: "gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // DSN data source name
DefaultStringSize: 256, // string 类型字段的默认长度
DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
}), &gorm.Config{})
GORM 允许通过 DriverName 选项自定义 MySQL 驱动,例如:
import (
_ "example.com/my_mysql_driver"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
db, err := gorm.Open(mysql.New(mysql.Config{
DriverName: "my_mysql_driver",
DSN: "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local", // data source name, 详情参考:https://github.com/go-sql-driver/mysql#dsn-data-source-name
}), &gorm.Config{})
2.5.3 调试模式
db.Debug()
2.5.4 连接池配置
sqlDB, _ := db.DB()
//设置数据库连接池参数
sqlDB.SetMaxOpenConns(100) //设置数据库连接池最大连接数
sqlDB.SetMaxIdleConns(20) //连接池最大允许的空闲连接数,如果没有sql任务需要执行的连接数大于20,超过的连接会被连接池关闭
下一篇文章的 gorm的增删改查 (crud)