GORM #
特性 #
- 全功能 ORM
- 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
- Create,Save,Update,Delete,Find 中钩子方法
- 支持
Preload
、Joins
的预加载 - 事务,嵌套事务,Save Point,Rollback To Saved Point
- Context、预编译模式、DryRun 模式
- 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
- SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
- 复合主键,索引,约束
- Auto Migration
- 自定义 Logger
- 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
- 每个特性都经过了测试的重重考验
- 开发者友好
安装 #
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
快速入门 #
package main
import (
"gorm.io/gorm"
"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")
}
// 迁移 schema
db.AutoMigrate(&Product{})
// Create
db.Create(&Product{Code: "D42", Price: 100})
// Read
var product Product
db.First(&product, 1) // 根据整形主键查找
db.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录
// Update - 将 product 的 price 更新为 200
db.Model(&product).Update("Price", 200)
// Update - 更新多个字段
db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段
db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})
// Delete - 删除 product
db.Delete(&product, 1)
}
字段标签 #
标签是声明模型时可选的标记,标记不区分大小写,GORM 支持以下标记:
声明model时,tag是可选的,GORM支持以下tag:tag名大小写不敏感,但建议使用camelcase风格
标签名 | 说明 |
---|---|
column | 指定列名 |
type | 列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持bool、int、uint、float、string、time、bytes并且可以和其他标签一起使用,例如:not null、size、autoIncrement…像varbinary(8)这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT、UNSIGNED、not、NULL、AUTO、INSTREMENT |
size | 指定列大小,例如:size: 256 |
primaryKey | 指定列为主键 |
unique | 指定列为唯一 |
default | 指定列的默认值 |
precision | 指定列的精度 |
scale | 指定列大小 |
not null | 不能为空 |
autolncrement | 指定列为自动增长 |
embedded | 嵌套字段 |
embeddedPrefix | 嵌入字段的列名前缀 |
autoCreateTime | 创建时追踪当前时间,对于int字段,它会追踪时间戳秒数,您可以使用nano/milli来追踪纳秒、毫秒时间戳,例如autoCreateTime:nano |
autoUpdateTime | 创建/更新时追踪当前时间,对于int字段,它会追踪时间戳秒数,您可以使用nano/milli来追踪纳秒、毫秒时间戳,例如:autoupdateTime:milli |
index | 根据参数创建索引1,多个字段使用相同的名称则创建复合索引,查看索引获取详情 |
uniqueindex | 与index相同,但创建的是唯一索引 |
check | 创建检查约束,例如check:age>13查看约束获取详情 |
<- | 设置字段写入的权限,<-:create只创建、<-:update只更新、<-:false无写入权限、「<-创建和更新权限 |
-> | 设置字段读的权限,->:false无读权限 |
- | 忽略该字段,-无读写权限 |
gorm使用中遇到的坑点 #
3、Count方法不适合放在raw方法后面,否则将会出错
count:=0
db.Raw(sql).Count(&count)
正确用法
db.Model(&User{}).Where("name = ?", "jinzhu").Count(&count)
//正确用法
result := engine.Raw(querySQL, args...).Find(resultData)
if result.Error != nil {
err = fmt.Errorf("find data in table error:%s", err.Error())
return
} else {
count = result.RowsAffected
}
https://blog.csdn.net/weixin_44267448/article/details/104271850
limit默认值如果为0,则需要手动赋值为-1,否则查不出来
eng := engine.Table(tableName).Where("pid=?", pid)
err = eng.Limit(limit).Offset(skip).Count(&nCount).Find(&resultData).Error
输入框对”%“ ”_“特殊字符的处理 #
在 SQL 中,_
和 %
是通配符,用于 LIKE
操作符中的字符串匹配。以下是它们的含义:
%
:匹配任意多个字符
-
%
可以匹配零个或多个字符。 -
示例:
name LIKE 'user%'
匹配:
user
,user1
,user_abc
,userXYZ
, 等等。查询:
name LIKE '%test%'
匹配:
test
,mytest
,unittesting
, 等等。
_
:匹配单个字符
-
_
可以匹配任意单个字符。 -
示例:
查询:
name LIKE 'user_'
匹配:
user1
,userA
,user_
,但不匹配user12
或user
.查询:
name LIKE '_test'
匹配:
1test
,A_test
,Ztest
,但不匹配ABtest
.
if strings.Contains(name, "_") {
name = strings.ReplaceAll(name, "_", "\\_")
}
if strings.Contains(name, "%") {
name = strings.ReplaceAll(name, "%", "\\%")
}
func (es *RecordService) GetRecords(limit, offset int, name, evidenceType string) (count int64, evidences []vmodel.Evidence, err error) {
var items []string
var args []interface{}
if name != "" {
items = append(items, "(`name` like ? ESCAPE '\\')")
args = append(args, "%"+name+"%")
}
if evidenceType != "" {
items = append(items, "(`type` like ?)")
args = append(args, "%"+evidenceType+"%")
}
keywordSQL := strings.Join(items, " and ")
count, evidences, err = proxy.Record.GetRecords(limit, offset, keywordSQL, args, false)
if err != nil {
common.Log.Error(err)
return
}
return
}
func (ep *RecordProxy) GetRecords(limit, offset int, keywordSQL string, args []interface{}, isAll bool) (count int64, evidences []vmodel.Evidence, err error) {
masterDBProxy, err := db.GetDBInstance().GetMasterDB()
if err != nil {
return
}
if isAll {
err = masterDBProxy.Model(&vmodel.Evidence{}).Unscoped().Where(keywordSQL, args...).Count(&count).Limit(limit).Offset(offset).Find(&evidences).Error
} else {
//为了防止更改磁盘信息导致查不出记录列表 只查询用到的列
err = masterDBProxy.Model(&vmodel.Evidence{}).Where(keywordSQL, args...).Select("id,case_id,name,brand_name,type,evidence_infos,partitions,brand_type,location,create_at,update_at,disk_info").Count(&count).Limit(limit).Offset(offset).Order("update_at desc").Find(&evidences).Error
}
return
}