如何使用 GORM | 青训营

145 阅读7分钟

1.概述

GORM是Golang目前比较热门的数据库ORM操作库,对开发者也比较友好,使用非常方便简单,使用上主要就是把struct类型和数据库表记录进行映射,操作数据库的时候不需要直接手写Sql代码,这里主要介绍MySQL数据库。
GORM库github地址: github.com/go-gorm/gor…

2.简单例子

我们先看个简单的例子了解下GORM大概怎么使用

2.1. 安装依赖包

操作MySQL需要安装两个包:

  • MySQL驱动包
  • GORM包 使用go get命令安装依赖包
//安装MySQL驱动
go get -u gorm.io/driver/mysql
//安装gorm包
go get -u gorm.io/gorm

2.2. 导入依赖包

import (
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
)

2.3. GORM操作MYSQL例子

使用gorm库操作MYSQL步骤:

  1. 使用struct定义模型,模型主要用在golang中代表mysql表
  2. 使用gorm创建数据库连接
  3. 使用gorm操作数据库。

下面是例子用到的users表结构定义

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` int(10) NOT NULL DEFAULT 0 COMMENT '创建时间',
   PRIMARY KEY (`id`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8

代码示例

package main

import (
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
  "fmt"
  "time"
  "errors"
)

//定义User模型,绑定users表,ORM库操作数据库,需要定义一个struct类型和MYSQL表进行绑定或者叫映射,struct字段和MYSQL表字段一一对应
//在这里User类型可以代表mysql users表
type User struct {
        ID int64 // 主键
	//通过在字段后面的标签说明,定义golang字段和表字段的关系
	//例如 `gorm:"column:username"` 标签说明含义是: Mysql表的列名(字段名)为username
	//这里golang定义的Username变量和MYSQL表字段username一样,他们的名字可以不一样。
	Username string `gorm:"column:username"`
	Password string `gorm:"column:password"`
	//创建时间,时间戳
	CreateTime int64 `gorm:"column:createtime"`
}

//设置表名,可以通过给struct类型定义 TableName函数,返回当前struct绑定的mysql表名是什么
func (u User) TableName() string {
	//绑定MYSQL表名为users
	return "users"
}

func main()  {
	//配置MySQL连接参数
	username := "root"  //账号
	password := "123456" //密码
	host := "127.0.0.1" //数据库地址,可以是Ip或者域名
	port := 3306 //数据库端口
	Dbname := "tizi365" //数据库名

	//通过前面的数据库参数,拼接MYSQL DSN, 其实就是数据库连接串(数据源名称)
	//MYSQL dsn格式: {username}:{password}@tcp({host}:{port})/{Dbname}?charset=utf8&parseTime=True&loc=Local
	//类似{username}使用花括号包着的名字都是需要替换的参数
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", username, password, host, port, Dbname)
	//连接MYSQL
        db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})

	if err != nil {
		panic("连接数据库失败, error=" + err.Error())
	}

	//定义一个用户,并初始化数据
	u := User{
		Username:"tizi365",
		Password:"123456",
		CreateTime:time.Now().Unix(),
	}

	//插入一条用户数据
	//下面代码会自动生成SQL语句:INSERT INTO `users` (`username`,`password`,`createtime`) VALUES ('tizi365','123456','1540824823')
	if err := db.Create(&u).Error; err != nil {
		fmt.Println("插入失败", err)
		return
	}

	//查询并返回第一条数据
	//定义需要保存数据的struct变量
	u = User{}
	//自动生成sql: SELECT * FROM `users`  WHERE (username = 'tizi365') LIMIT 1
	result := db.Where("username = ?", "tizi365").First(&u)
	if errors.Is(result.Error, gorm.ErrRecordNotFound) {
		fmt.Println("找不到记录")
		return
	}
	//打印查询到的数据
	fmt.Println(u.Username,u.Password)

	//更新
	//自动生成Sql: UPDATE `users` SET `password` = '654321'  WHERE (username = 'tizi365')
	db.Model(&User{}).Where("username = ?", "tizi365").Update("password", "654321")

	//删除
	//自动生成Sql: DELETE FROM `users`  WHERE (username = 'tizi365')
	db.Where("username = ?", "tizi365").Delete(&User{})
}

3. gorm错误处理

gorm库在执行数据库操作的时候,如果出现错误,则会更新gorm.DB的Error属性,Error属性默认为nil,因此在执行数据库操作后检测下Error属性是否为nil即可知道有没有错误发生。

//插入记录后,检测Error是否为nil
if err := db.Create(u).Error; err != nil {
		fmt.Println("插入失败", err)
		return
}

GORM模型定义

1.前言

ORM框架操作数据库都需要预先定义模型,模型可以理解成数据模型,作为操作数据库的媒介。
例如:

  • 从数据库读取的数据会先保存到预先定义的模型对象,然后我们就可以从模型对象得到我们想要的数据。
  • 插入数据到数据库也是先新建一个模型对象,然后把想要保存的数据先保存到模型对象,然后把模型对象保存到数据库。

在golang中gorm模型定义是通过struct实现的,这样我们就可以通过gorm库实现struct类型和mysql表数据的映射。

提示:gorm负责将对模型的读写操作翻译成sql语句,然后gorm再把数据库执行sql语句后返回的结果转化为我们定义的模型对象。

2.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字段名使用Snake Case命名风格转换成mysql表字段名(需要转换成小写字母)。
根据gorm的默认约定,上面例子只需要使用gorm:"column:createtime"标签定义为CreateTime字段指定表字段名,其他使用默认值即可。

提示:Snake Case命名风格,就是各个单词之间用下划线(_)分隔,例如: CreateTime的Snake Case风格命名为create_time

3.gorm模型标签

通过上面的例子,大家看到可以通过类似gorm:"column:createtime"这样的标签定义语法,定义struct字段的列名(表字段名)。
gorm标签语法:gorm:"标签定义"

标签定义部分,多个标签定义可以使用分号(;)分隔

例如定义列名:

gorm:"column:列名"

gorm常用标签如下:

标签说明例子
column指定列名gorm:"column:createtime"
primaryKey指定主键gorm:"column:id; PRIMARY_KEY"
-忽略字段gorm:"-" 可以忽略struct字段,被忽略的字段不参与gorm的读写操作

4.定义表名

可以通过定义struct类型的TableName函数实现定义模型的表名

接上面的例子:

//设置表名,可以通过给Food struct类型定义 TableName函数,返回一个字符串作为表名
func (v Food) TableName() string {
	return "food"
}

建议: 默认情况下都给模型定义表名,有时候定义模型只是单纯的用于接收手写sql查询的结果,这个时候是不需要定义表名;手动通过gorm函数Table()指定表名,也不需要给模型定义TableName函数。

5.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
}

6.自动更新时间

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"`      //自定义字段, 使用时间戳秒数填充创建时间
}