## gorm
ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping) 的缩写.
gorm, github.com/jinzhu/gorm 全特性 ORM (几乎包含所有特性).
## 模型定义
模型一般都是普通的 Golang 的结构体,Go 的基本数据类型,或者指针。sql.Scanner 和 driver.Valuer,同时也支持接口。
### gorm.Model
gorm.Model 是一个包含一些基本字段的结构体,包含的字段有 ID,CreatedAt, UpdatedAt, DeletedAt。
你可以用它来嵌入到你的模型中,或者也可以用它来建立自己的模型.GORM 默认使用 ID 作为主键名。
- 可以通过`gorm:"primary_key"设置主键.
- 表名是结构体名称的复数形式, type User struct{} 默认表名是"users", 可以重写TableName() string 返回新表名
- 禁用复数表名:db.SingularTable(true)
- 修改默认表名gorm.DefaultTableNameHandler
```
gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string {
return "prefix_" + defaultTableName;
}
```
- 蛇形列名,列名是字段名的蛇形小写形式
```
type User struct {
ID uint // 字段名是 `id`
Name string // 字段名是 `name`
Birthday time.Time // 字段名是 `birthday`
CreatedAt time.Time // 字段名是 `created_at`
}
```
### 结构标签
标签 说明
Column 指定列的名称
Type 指定列的类型
Size 指定列的大小,默认是 255
PRIMARY_KEY 指定一个列作为主键
UNIQUE 指定一个唯一的列
DEFAULT 指定一个列的默认值
PRECISION 指定列的数据的精度
NOT NULL 指定列的数据不为空
AUTO_INCREMENT 指定一个列的数据是否自增
INDEX 创建带或不带名称的索引,同名创建复合索引
UNIQUE_INDEX 类似 索引,创建一个唯一的索引
EMBEDDED 将 struct 设置为 embedded
EMBEDDED_PREFIX 设置嵌入式结构的前缀名称
- 忽略这些字段
FOREIGNKEY 指定外键
```
type User struct {
gorm.Model
Name string `gorm:"default:aa"`
Age sql.NullInt64
Birthday *time.Time `gorm:"column:day_of_the_beast"`
Email string `gorm:"type:varchar(100);unique_index"`
Role string `gorm:"size:255"` //设置字段的大小为255个字节
MemberNumber *string `gorm:"unique;not null"` // 设置 memberNumber 字段唯一且不为空
Num int `gorm:"AUTO_INCREMENT"` // 设置 Num字段自增
Address string `gorm:"index:addr"` // 给Address 创建一个名字是 `addr`的索引
IgnoreMe int `gorm:"-"` //忽略这个字段
}
```
## CRUD
### 连接
```
import (
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
)
db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
defer db.Close()
```
### 创建记录
```
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
db.Create(&user)
//在钩子中设置字段值
func (user *User) BeforeCreate(scope *gorm.Scope) error {
scope.SetColumn("ID", uuid.New())
return nil
}
```
### 查询记录
db.First()
db.Find()
db.Where().Find()
db.Raw()
db.Exec()
```
// 获取第一条记录,按主键排序
db.First(&user) // SELECT * FROM users ORDER BY id LIMIT 1;
// 获取所有的记录
db.Find(&users) // SELECT * FROM users;
// 通过主键进行查询
db.First(&user, 10) // SELECT * FROM users WHERE id = 10;
// 原生 SQL
db.Find(&user, "name = ?", "jinzhu") // SELECT * FROM users WHERE name = "jinzhu";
db.Find(&users, "name <> ? AND age > ?", "jinzhu", 20) // SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;
// Struct
db.Find(&users, User{Age: 20}) // SELECT * FROM users WHERE age = 20;
// 获取第一条匹配的记录
db.Where("name = ?", "jinzhu").First(&user) // SELECT * FROM users WHERE name = 'jinzhu' limit 1;
// 获取所有匹配的记录
db.Where("name = ?", "jinzhu").Find(&users) // SELECT * FROM users WHERE name = 'jinzhu';
//struct
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user) // SELECT * FROM users WHERE name = "jinzhu" AND age = 20 LIMIT 1;
// Map
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users) // SELECT * FROM users WHERE name = "jinzhu" AND age = 20;
type Result struct {
Name string
Age int
}
var result Result
db.Table("users").Select("name, age").Where("name = ?", 3).Scan(&result)
// Raw SQL
db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result)
```
### 更新记录
db.Save() //更新所有字段
db.Model(&struct).Update(k,v) //更新特定字段
```
db.First(&user)
user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
//// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;
// 如果单个属性被更改了,更新它
db.Model(&user).Update("name", "hello")
//// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;
```
### 删除记录
```
// 删除一条存在的记录
db.Delete(&email)
db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})
```
## 高级
### 钩子
钩子是一个在 插入 / 查询 / 更新 / 删除 之前或之后被调用的方法。
如果你在一个模型中定义了特殊的方法,它将会在插入,更新,查询,删除的时候被自动调用,如果任何的回调抛出错误,GORM 将会停止将要执行的操作并且回滚当前的改变
在 GORM 中的保存 / 删除 操作会默认进行事务处理,所以在事物中,所有的改变都是无效的,直到它被提交为止
可用于更新的钩子:
// 开启事务
BeforeSave
BeforeUpdate
AfterUpdate
AfterSave
// 提交或回滚的事务
```
func (u *User) BeforeSave() (err error) {
if u.IsValid() {
err = errors.New("can't save invalid data")
}
return
}
func (u *User) AfterCreate(scope *gorm.Scope) (err error) {
if u.ID == 1 {
scope.DB().Model(u).Update("role", "admin")
}
return
}
func (u *User) BeforeUpdate() (err error) {
if u.readonly() {
err = errors.New("read only user")
}
return
}
// 在事务结束后,进行更新数据
func (u *User) AfterUpdate(tx *gorm.DB) (err error) {
if u.Confirmed {
tx.Model(&Address{}).Where("user_id = ?", u.ID).Update("verfied", true)
}
return
}
// 在事务结束后进行更新数据
func (u *User) AfterDelete(tx *gorm.DB) (err error) {
if u.Confirmed {
tx.Model(&Address{}).Where("user_id = ?", u.ID).Update("invalid", false)
}
return
}
```
### 事务
GORM 默认在事务中执行单个 create, update, delete 操作,以确保数据库数据完整性。
```
/ 开启事务
tx := db.Begin()
// 在事务中执行一些数据库操作 (从这里开始使用 'tx',而不是 'db')
tx.Create(...)
// ...
// 发生错误回滚事务
tx.Rollback()
// 或者提交这个事务
tx.Commit()
```
有疑问加站长微信联系(非本文作者))