Go GORM 使用[转]
参考文章
安装
//安装MySQL驱动
go get -u gorm.io/driver/mysql
//安装gorm包
go get -u gorm.io/gorm
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
- 在golang中gorm模型定义是通过struct实现的,这样我们就可以通过gorm库实现struct类型和mysql表数据的映射。
- 提示:gorm负责将对模型的读写操作翻译成sql语句,然后gorm再把数据库执行sql语句后返回的结果转化为我们定义的模型对象。
gorm模型定义
- gorm模型定义主要就是在struct类型定义的基础上增加字段标签说明实现,下面看个完整的例子。假如有个商品表,表结构如下
CREATE TABLE `food` (
`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=utf8
//字段注释说明了gorm库把struct字段转换为表字段名长什么样子。
type Food struct {
Id int //表字段名为:id
Name string //表字段名为:name
Price float64 //表字段名为:price
TypeId int //表字段名为:type_id
//字段定义后面使用两个反引号``包裹起来的字符串部分叫做标签定义,这个是golang的基础语法,不同的库会定义不同的标签,有不同的含义
CreateTime int64 `gorm:"column:createtime"` //表字段名为:createtime
}
gorm常用标签
定义表名
- 可以通过定义struct类型的TableName函数实现定义模型的表名
//设置表名,可以通过给Food struct类型定义 TableName函数,返回一个字符串作为表名
func (v Food) TableName() string {
return "food"
}
- 建议: 默认情况下都给模型定义表名,有时候定义模型只是单纯的用于接收手写sql查询的结果,这个时候是不需要定义表名;手动通过gorm函数Table()指定表名,也不需要给模型定义TableName函数。
gorm.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"`
}
- 以将它嵌入到我们的结构体中,就以包含这几个字段,类似继承的效果。
type User struct {
gorm.Model // 嵌入gorm.Model的字段
Name string
}
自动更新时间
- 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"` //自定义字段, 使用时间戳秒数填充创建时间
}
gorm连接数据库
- gorm支持多种数据库,这里主要介绍mysql,连接mysql主要有两个步骤:
- 1)配置DSN (Data Source Name)
- 2)使用gorm.Open连接数据库
配置DSN (Data Source Name)
- gorm库使用dsn作为连接数据库的参数,dsn翻译过来就叫数据源名称,用来描述数据库连接信息。一般都包含数据库连接地址,账号,密码之类的信息。
- DSN格式:
[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN]
//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 = tizi365
//后面K/V键值对参数含义为:
// charset=utf8 客户端字符集为utf8
// parseTime=true 支持把数据库datetime和date类型转换为golang的time.Time类型
// loc=Local 使用系统本地时区
root:123456@tcp(localhost:3306)/tizi365?charset=utf8&parseTime=True&loc=Local
//gorm 设置mysql连接超时参数
//开发的时候经常需要设置数据库连接超时参数,gorm是通过dsn的timeout参数配置
//例如,设置10秒后连接超时,timeout=10s
//下面是完成的例子
root:123456@tcp(localhost:3306)/tizi365?charset=utf8&parseTime=True&loc=Local&timeout=10s
//设置读写超时时间
// readTimeout - 读超时时间,0代表不限制
// writeTimeout - 写超时时间,0代表不限制
root:123456@tcp(localhost:3306)/tizi365?charset=utf8&parseTime=True&loc=Local&timeout=10s&readTimeout=30s&writeTimeout=60s
使用gorm.Open连接数据库
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
//配置MySQL连接参数
username := "root" //账号
password := "root" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
Dbname := "db1" //数据库名
timeout := "10s" //连接超时,10秒
//拼接下dsn参数, dsn格式可以参考上面的语法,这里使用Sprintf动态拼接dsn参数,因为一般数据库连接参数,我们都是保存在配置文件里面,需要从配置文件加载参数,然后拼接dsn。
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local&timeout=%s", username, password, host, port, Dbname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
_, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}else{
fmt.Println("连接成功")
}
//延时关闭数据库连接 新版本已经没有这个方法了
//defer db.Close()
}
gorm调试模式
- 为了方便调试,了解gorm操作到底执行了怎么样的sql语句,开发的时候需要打开调试日志,这样gorm会打印出执行的每一条sql语句。
- 使用Debug函数执行查询即可
result := db.Debug().Where("username = ?", "tizi365").First(&u)
gorm连接池
- 在高并发实践中,为了提高数据库连接的使用率,避免重复建立数据库连接带来的性能消耗,会经常使用数据库连接池技术来维护数据库连接。
- gorm自带了数据库连接池使用非常简单只要设置下数据库连接池参数即可。
- 数据库连接池使用例子:
- 定义tools包,负责数据库初始化工作(备注:借助连接池说明,一般在操作数据库时,可以将数据库连接单独封装成一个包)
package tool
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
//定义全局的db对象,我们执行数据库操作主要通过他实现。
var _db *gorm.DB
//包初始化函数,golang特性,每个包初始化的时候会自动执行init函数,这里用来初始化gorm。
func init() {
//配置MySQL连接参数
username := "root" //账号
password := "root" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
Dbname := "db1" //数据库名
timeout := "10s" //连接超时,10秒
//拼接下dsn参数, dsn格式可以参考上面的语法,这里使用Sprintf动态拼接dsn参数,因为一般数据库连接参数,我们都是保存在配置文件里面,需要从配置文件加载参数,然后拼接dsn。
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local&timeout=%s", username, password, host, port, Dbname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
_db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}else{
fmt.Println("连接成功")
}
sqlDB, error := _db.DB()
if error != nil{
panic("获取数据库失败, error=" + error.Error())
}
//设置数据库连接池参数
sqlDB.SetMaxOpenConns(100) //设置数据库连接池最大连接数
sqlDB.SetMaxIdleConns(20) //连接池最大允许的空闲连接数,如果没有sql任务需要执行的连接数大于20,超过的连接会被连接池关闭。
}
//获取gorm db对象,其他包需要执行数据库查询的时候,只要通过tools.getDB()获取db对象即可。
//不用担心协程并发使用同样的db对象会共用同一个连接,db对象在调用他的方法的时候会从数据库连接池中获取新的连接
func GetDB() *gorm.DB {
return _db
}
package main
import (
"gin_demo/tool"
"time"
)
type User struct {
CreatedAt time.Time // 默认创建时间字段, 在创建时,如果该字段值为零值,则使用当前时间填充
UpdatedAt int // 默认更新时间字段, 在创建时该字段值为零值或者在更新时,使用当前时间戳秒数填充
Created int64 `gorm:"autoCreateTime"` //自定义字段, 使用时间戳秒数填充创建时间
}
func main() {
//获取DB
db := tool.GetDB()
//执行数据库查询操作
u := User{}
//自动生成sql: SELECT * FROM `users` WHERE (username = 'tizi365') LIMIT 1
db.Where("username = ?", "db1").First(&u)
}