GORM 基础

官网
Gen Guides

特性:

  • 功能齐全的ORM
  • 关联(一个、有多个、属于、多对多、多态性、单表继承)
  • 钩子(Hooks)(创建/保存/更新/删除/查找之前/之后)
  • 使用Preload和join进行快速加载
  • 事务,嵌套事务,保存点,回滚到保存点
  • 上下文,准备语句模式,DryRun模式
  • 批量插入,批量查找,查找映射
  • SQL Builder, Upsert,锁定,优化器/索引/注释提示,命名参数,用SQL Expr 搜索/更新/创建
  • 复合主键
  • 自动迁移
  • 日志
  • 可扩展的,灵活的插件API:数据库解析器(多数据库,读/写拆分)/ Prometheus…
  • 每个特性都可测试
  • 开发友好

Go 使用MySQL数据库

Go中支持MySQL的驱动目前比较多,有如下几种,有些是支持database/sql标准,而有些是采用了自己的实现接口,常用的有如下几种:

https://github.com/go-sql-driver/mysql 支持database/sql,全部采用go写。
https://github.com/ziutek/mymysql 支持database/sql,也支持自定义的接口,全部采用go写。

主要以第一个驱动为例(我目前项目中也是采用它来驱动),也推荐大家采用它,主要理由:

这个驱动比较新,维护的比较好
完全支持database/sql接口
支持keepalive,保持长连接,虽然mymysql也支持keepalive,但不是线程安全的,这个从底层就支持了keepalive。

1、概览

go get -u gorm.io/gorm
go get -u 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")
  }

  // Migrate the schema
  db.AutoMigrate(&Product{})

  // Create
  db.Create(&Product{Code: "D42", Price: 100})

  // Read
  var product Product
  db.First(&product, 1) // find product with integer primary key
  db.First(&product, "code = ?", "D42") // find product with code D42

  // Update - update product's price to 200
  db.Model(&product).Update("Price", 200)
  // Update - update multiple fields
  db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // non-zero fields
  db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})

  // Delete - delete product
  db.Delete(&product, 1)
}

2、声明模型(Declaring Models)

2.1 Declaring Models

模型是具有基本Go类型、指针/别名或实现ScannerValuer接口的自定义类型的普通结构
例如:

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
}

2.2 约定(Conventions)

GORM更喜欢约定而不是配置。默认情况下,GORM使用ID作为主键,将结构名复数为snake_cases作为表名,snake_case作为列名,并使用CreatedAtUpdatedAt跟踪创建/更新时间

如果您遵循GORM采用的约定,您将需要编写非常少的配置/代码。如果约定不符合您的需求,GORM允许您配置它们

2.3 gorm.Model

GORM defined a gorm.Model struct, which includes fields ID, CreatedAt, UpdatedAt, DeletedAt

// gorm.Model definition
type Model struct {
  ID        uint           `gorm:"primaryKey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`
}

可以将其嵌入到结构中以包含这些字段,参考嵌入式结构体

2.4 高级设置

2.4.1 字段级权限

当使用GORM进行CRUD时,导出的字段具有所有权限,并且GORM允许您使用标记更改字段级别的权限,因此您可以将字段设置为只读只写仅创建仅更新忽略 (read-only, write-only, create-only, update-only or ignored)

当使用GORM Migrator创建表时,忽略字段将不会被创建

type User struct {
  Name string `gorm:"<-:create"` // allow read and create
  Name string `gorm:"<-:update"` // allow read and update
  Name string `gorm:"<-"`        // allow read and write (create and update)
  Name string `gorm:"<-:false"`  // allow read, disable write permission
  Name string `gorm:"->"`        // readonly (disable write permission unless it configured)
  Name string `gorm:"->;<-:create"` // allow read and create
  Name string `gorm:"->:false;<-:create"` // createonly (disabled read from db)
  Name string `gorm:"-"`            // ignore this field when write and read with struct
  Name string `gorm:"-:all"`        // ignore this field when write, read and migrate with struct
  Name string `gorm:"-:migration"`  // ignore this field when migrate with struct
}

2.4.2 Creating/Updating Time/Unix (Milli/Nano) Seconds Tracking

GORM使用CreatedAt, UpdatedAt来按照约定跟踪创建/更新时间,如果定义了字段,GORM将在创建/更新时设置当前时间

要使用不同名称的字段,您可以使用标记autoCreateTime, autoUpdateTime来配置这些字段

如果您希望保存 UNIX (milli/nano) 秒而不是时间,您可以简单地根据更改字段的数据类型 time.Timeint

type User struct {
  CreatedAt time.Time // Set to current time if it is zero on creating
  UpdatedAt int       // Set to current unix seconds on updating or if it is zero on creating
  Updated   int64 `gorm:"autoUpdateTime:nano"` // Use unix nano seconds as updating time
  Updated   int64 `gorm:"autoUpdateTime:milli"`// Use unix milli seconds as updating time
  Created   int64 `gorm:"autoCreateTime"`      // Use unix seconds as creating time
}

2.4.3 嵌入式结构

对于匿名字段(anonymous fields),GORM将把它的字段包含到它的父结构体中,例如:

type User struct {
  gorm.Model
  Name string
}
// equals
type User struct {
  ID        uint           `gorm:"primaryKey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`
  Name string
}

对于一个普通的struct字段,你可以embedded标签,例如:

type Author struct {
  Name  string
  Email string
}

type Blog struct {
  ID      int
  Author  Author `gorm:"embedded"`
  Upvotes int32
}
// equals
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
}
// equals
type Blog struct {
  ID          int64
  AuthorName  string
  AuthorEmail string
  Upvotes     int32
}

2.4.4 字段标签

在声明模型(model)时,标签是可选的,GORM支持以下标签:
标签是不区分大小写的,但是camelCase是首选的

Tag NameDescription
columncolumn db name
typecolumn data type, 首选使用兼容的通用型, e.g: bool, int, uint, float, string, time, bytes, 对所有数据库都适用, 可以和其他标签(tag)一起使用, like not null, size, autoIncrement… specified database data type like varbinary(8) also supported, when using specified database data type, it needs to be a full database data type, for example: MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT
serializerspecifies serializer for how to serialize and deserialize data into db, e.g: serializer:json/gob/unixtime
sizespecifies column data size/length, e.g: size:256
primaryKeyspecifies column as primary key
uniquespecifies column as unique
defaultspecifies column default value
precisionspecifies column precision
scalespecifies column scale
not nullspecifies column as NOT NULL
autoIncrementspecifies column auto incrementable
autoIncrementIncrementauto increment step, 控制连续列值之间的间隔
embeddedembed the field
embeddedPrefixcolumn name prefix for embedded fields
autoCreateTimetrack current time when creating, for int fields, it will track unix seconds, use value nano/milli to track unix nano/milli seconds, e.g: autoCreateTime:nano
autoUpdateTimetrack current time when creating/updating, for int fields, it will track unix seconds, use value nano/milli to track unix nano/milli seconds, e.g: autoUpdateTime:milli
indexcreate index with options, use same name for multiple fields creates composite indexes, refer Indexes for details
uniqueIndexsame as index, but create uniqued index
checkcreates check constraint, eg: check:age > 13, refer Constraints
<-set field’s write permission, <-:create create-only field, <-:update update-only field, <-:false no write permission, <- create and update permission
->set field’s read permission, ->:false no read permission
-ignore this field, - no read/write permission, -:migration no migrate permission, -:all no read/write/migrate permission
commentadd comment for field when migration

2.4.5 关联标签(Associations Tags)

GORM允许配置外键(foreign keys),约束(constraints),多对多(many2many)表通过标签的关联,查看关联部分的详细信息

3、连接数据库

GORM正式支持MySQL、PostgreSQL、SQLite、SQL Server、TiDB等数据库

3.1 MySQL

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

func main() {
  // refer https://github.com/go-sql-driver/mysql#dsn-data-source-name for details
  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{})
}

要正确处理time.Time,您需要包括parseTime作为参数。(更多参数)
要完全支持UTF-8编码,需要将charset=utf8更改为charset=utf8mb4。有关详细解释,请参阅这篇文章

MySQL Driver提供了一些可以在初始化时使用的高级配置,例如:

db, err := gorm.Open(mysql.New(mysql.Config{
  DSN: "gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // data source name
  DefaultStringSize: 256, // string 字段的默认大小
  DisableDatetimePrecision: true, // 禁用datetime精度, which not supported before MySQL 5.6
  DontSupportRenameIndex: true, // drop & create when rename index, rename index not supported before MySQL 5.7, MariaDB
  DontSupportRenameColumn: true, // `change` when rename column, rename column not supported before MySQL 8, MariaDB
  SkipInitializeWithVersion: false, // 根据当前MySQL版本自动配置
}), &gorm.Config{})

3.1.1 定制 Driver

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, refer https://github.com/go-sql-driver/mysql#dsn-data-source-name
}), &gorm.Config{})

3.1.2 已有数据库连接

GORM 允许使用已有的数据库连接初始化*gorm.DB

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

sqlDB, err := sql.Open("mysql", "mydb_dsn")
gormDB, err := gorm.Open(mysql.New(mysql.Config{
  Conn: sqlDB,
}), &gorm.Config{})

3.2 连接池

GORM使用database/sql维护连接池

sqlDB, err := db.DB()

// SetMaxIdleConns sets the maximum number of connections in the idle connection pool.
sqlDB.SetMaxIdleConns(10)

// SetMaxOpenConns sets the maximum number of open connections to the database.
sqlDB.SetMaxOpenConns(100)

// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
sqlDB.SetConnMaxLifetime(time.Hour)

详细信息请参阅通用接口(Generic Interface)

3.3 Unsupported Databases

有些数据库可能与mysqlpostgresdialect兼容,在这种情况下,您可以在这些数据库中使用dialect。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值