GORM

什么是ORM?
Object Relational Mapping 对象关系映射

官方网站:https://gorm.io/

Go语言中结构体与数据库的关系

数据表 == 结构体
数据行 == 结构体实例
数据表字段 == 结构体字段

安装GORM
go get -u github.com/jinzhu/gorm
导入GORM
导入对应的数据库驱动:

连接不同的数据库都需要导入对应数据的驱动程序,GORM已经贴心的为我们包装了一些驱动程序,只需要按如下方式导入需要的数据库驱动即可:

import _ "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"
链接实例:

MySQL

import (
  "github.com/jinzhu/gorm"
  _ "github.com/jinzhu/gorm/dialects/mysql"
)

func main() {
  db, err := gorm.Open("mysql", "user:password@(localhost)/dbname?charset=utf8mb4&parseTime=True&loc=Local")
  defer db.Close()
}

postgres

import (
  "github.com/jinzhu/gorm"
  _ "github.com/jinzhu/gorm/dialects/postgres"
)

func main() {
  db, err := gorm.Open("postgres", "host=myhost port=myport user=gorm dbname=gorm password=mypassword")
  defer db.Close()
}

sqlite

import (
  "github.com/jinzhu/gorm"
  _ "github.com/jinzhu/gorm/dialects/sqlite"
)

func main() {
  db, err := gorm.Open("sqlite3", "/tmp/gorm.db")
  defer db.Close()
}

sqlserver

import (
  "github.com/jinzhu/gorm"
  _ "github.com/jinzhu/gorm/dialects/mssql"
)

func main() {
  db, err := gorm.Open("mssql", "sqlserver://username:password@localhost:1433?database=dbname")
  defer db.Close()
}
拓展学习:

在本地的13306端口运行一个名为mysql8019,root用户名密码为root1234的MySQL容器环境:

docker run --name mysql8019 -p 13306:3306 -e MYSQL_ROOT_PASSWORD=root1234 -d mysql:8.0.19

在另外启动一个MySQL Client连接上面的MySQL环境,密码为上一步指定的密码root1234:

docker run -it --network host --rm mysql mysql -h127.0.0.1 -P13306 --default-character-set=utf8mb4 -uroot -p
#创建数据库
CREATE DATABASE db1;
模型定义

在使用ORM工具时,通常我们需要在代码中定义模型(Models)与数据库中的数据表进行映射,在GORM中模型(Models)通常是正常定义的结构体、基本的go类型或它们的指针。 同时也支持sql.Scannerdriver.Valuer接口(interfaces)。

gorm.Model

为了方便模型定义,GORM内置了一个gorm.Model结构体。gorm.Model是一个包含了ID, CreatedAt, UpdatedAt, DeletedAt四个字段的Golang结构体。

// gorm.Model 定义
type Model struct {
  ID        uint `gorm:"primary_key"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt *time.Time
}

你可以将它嵌入到你自己的模型中:

// 将 `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`字段注入到`User`模型中
type User struct {
  gorm.Model
  Name string
}

当然也可以完全使用自己的模型:

type User struct {
  ID           uint
  Name         string
  Email        *string
  Age          uint8
  Birthday     *time.Time
  MemberNumber sql.NullString
  ActivatedAt  sql.NullTime
  CreatedAt    time.Time
  UpdatedAt    time.Time
}

模型定义约定
//示例
type User struct {
  gorm.Model
  Name         string
  Age          sql.NullInt64
  Birthday     *time.Time
  Email        string  `gorm:"type:varchar(100);unique_index"`
  Role         string  `gorm:"size:255"` // 设置字段大小为255
  MemberNumber *string `gorm:"unique;not null"` // 设置会员号(member number)唯一并且不为空
  Num          int     `gorm:"AUTO_INCREMENT"` // 设置 num 为自增类型
  Address      string  `gorm:"index:addr"` // 给address字段创建名为addr的索引
  IgnoreMe     int     `gorm:"-"` // 忽略本字段
}

使用结构体声明模型时,标记(tags)是可选项。gorm支持以下标记:

Column						指定列名
Type						指定列数据类型
Size						指定列大小, 默认值255
PRIMARY_KEY					将列指定为主键
UNIQUE						将列指定为唯一
DEFAULT						指定列默认值
PRECISION					指定列精度
NOT NULL					将列指定为非 NULL
AUTO_INCREMENT				指定列是否为自增类型
INDEX						创建具有或不带名称的索引, 如果多个索引同名则创建复合索引
UNIQUE_INDEX				和 INDEX 类似,只不过创建的是唯一索引
EMBEDDED					将结构设置为嵌入
EMBEDDED_PREFIX				设置嵌入结构的前缀
-							忽略此字段

关联相关标记(tags):

MANY2MANY					指定连接表
FOREIGNKEY					设置外键
ASSOCIATION_FOREIGNKEY		设置关联外键
POLYMORPHIC					指定多态类型
POLYMORPHIC_VALUE			指定多态值
JOINTABLE_FOREIGNKEY		指定连接表的外键
ASSOCIATION_JOINTABLE_FOREIGNKEY				指定连接表的关联外键
SAVE_ASSOCIATIONS			是否自动完成 save 的相关操作
ASSOCIATION_AUTOUPDATE		是否自动完成 update 的相关操作
ASSOCIATION_AUTOCREATE		是否自动完成 create 的相关操作
ASSOCIATION_SAVE_REFERENCE	是否自动完成引用的 save 的相关操作
PRELOAD						是否自动完成预加载的相关操作
主键(Primary Key)

GORM 默认会使用名为ID的字段作为表的主键。

type User struct {
  ID   string // 名为`ID`的字段会默认作为表的主键
  Name string
}

// 使用`AnimalID`作为主键
type Animal struct {
  AnimalID int64 `gorm:"primary_key"`
  Name     string
  Age      int64
}
表名(Table Name)

表名默认就是结构体名称的复数,例如:

type User struct {} // 默认表名是 `users`

// 将 User 的表名设置为 `profiles`
func (User) TableName() string {
  return "profiles"
}

func (u User) TableName() string {
  if u.Role == "admin" {
    return "admin_users"
  } else {
    return "users"
  }
}

// 禁用默认表名的复数形式,如果置为 true,则 `User` 的默认表名是 `user`
db.SingularTable(true)

也可以通过Table()指定表名:

// 使用User结构体创建名为`deleted_users`的表
db.Table("deleted_users").CreateTable(&User{})

var deleted_users []User
db.Table("deleted_users").Find(&deleted_users)
//// SELECT * FROM deleted_users;

db.Table("deleted_users").Where("name = ?", "jinzhu").Delete()
//// DELETE FROM deleted_users WHERE name = 'jinzhu';

注意:结构体属性单词首字母要大写

列名(Column Name)

列名由字段名称进行下划线分割来生成:

type User struct {
  ID        uint      // column name is `id`
  Name      string    // column name is `name`
  Birthday  time.Time // column name is `birthday`
  CreatedAt time.Time // column name is `created_at`
}

可以使用结构体tag指定列名:

type Animal struct {
  AnimalId    int64     `gorm:"column:beast_id"`         // set column name to `beast_id`
  Birthday    time.Time `gorm:"column:day_of_the_beast"` // set column name to `day_of_the_beast`
  Age         int64     `gorm:"column:age_of_the_beast"` // set column name to `age_of_the_beast`
}
增加删除查找更新
package main

import (
	"fmt"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
)

//定义用户结构体
type User struct {
	//ID主键自增
	ID   int `gorm:"primary_key;AUTO_INCREMENT"`
	Name string
	Mail string
	//设置默认值
	Sex string `gorm:"default:'妖'"`
}

//继承gorm.Model
type TiemSub struct {
	gorm.Model
}

//链接数据库
func connect() *gorm.DB {
	db, err := gorm.Open("sqlite3", "gorm.db")
	fmt.Println("connect ERR: ", err)
	return db
}

//创建数据表
func createTab(db *gorm.DB) {
	db.AutoMigrate(&User{}, &TiemSub{})
}

//插入记录
func add(db *gorm.DB) {
	//创建对象插入
	u1 := User{Name: "root", Mail: "root@root"}
	db.Create(&u1)

	u2 := User{
		Name: "Mek",
		Mail: "030399",
		Sex:  "男",
	}

	db.Create(&u2)
}

//查询并更新或删除
func update(db *gorm.DB) {
	//查询
	var u1 = new(User)

	//条件查询
	db.Find(&u1, "name=?", "Mek")
	fmt.Println(u1.Mail, u1.Name)

	//查询后更新更新
	u1.Name = "ROOT"
	db.Save(&u1)
	fmt.Println("更新后!")
	db.Find(&u1, "name=?", "Mek")
	fmt.Println(u1.Mail, u1.Name)

	//批量更新更新
	db.Model(&User{}).Where("sex=?", "妖").Update("sex", "未知")

	//根据主键单独删除
	//删除主键为10的
	db.Delete(&User{}, 10)

	//批量删除
	db.Delete(&User{}, "mail = ?", "")
	db.Delete(&User{}, "mail LIKE ?", "%mmp%")
	// DELETE from emails where email LIKE "%jinzhu%";
}

func main() {
	db := connect()
	createTab(db)
	update(db)
}