> gorm查詢數據本質上就是提供一組函數,幫我們快速拼接sql語句,盡量減少編寫sql語句的工作量
[TOC]
## 測試表
~~~
CREATE TABLE `food` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '商品id',
`title` varchar(100) NOT NULL COMMENT '商品名',
`price` float DEFAULT '0' COMMENT '商品價格',
`stock` int(11) DEFAULT '0' COMMENT '商品庫存',
`type` int(11) DEFAULT '0' COMMENT '商品類型',
`create_time` datetime NOT NULL COMMENT '商品創建時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
~~~
## 模型定義
~~~
//商品
type Food struct {
Id int
Title string
Price float32
Stock int
Type int
//mysql datetime, date類型字段,可以和golang time.Time類型綁定, 詳細說明請參考:gorm連接數據庫章節。
CreateTime time.Time
}
//為Food綁定表名
func (v Food) TableName() string {
return "food"
}
~~~
## 使用gorm鏈式操作函數查詢數據
### query
**Take**
> 查詢一條記錄
~~~
food := Food{}
//等價于:SELECT * FROM `foods` LIMIT 1
db.Take(&food)
~~~
**Find**
> 查詢多條記錄,Find函數返回的是一個數組
~~~
var foods []Food
//等價于:SELECT * FROM `foods`
db.Find(&foods)
~~~
**Pluck**
> 查詢一列值
~~~
//商品標題數組
var titles []string
//返回所有商品標題
//等價于:SELECT title FROM `foods`
//Pluck提取了title字段,保存到titles變量
//這里Model函數是為了綁定一個模型實例,可以從里面提取表名。
db.Model(Food{}).Pluck("title", &titles)
~~~
**查詢錯誤處理**
> 通過db.Error屬性判斷查詢結果是否出錯, Error屬性不等于nil表示有錯誤發生
~~~
if err := db.Take(&food).Error; err != nil {
fmt.Println("查詢失敗", err)
}
~~~
> 查詢不到數據, gorm也會當成錯誤處理
~~~
err := db.Take(&food).Error
if gorm.IsRecordNotFoundError(err) {
fmt.Println("查詢不到數據")
} else if err != nil {
//如果err不等于record not found錯誤,又不等于nil,那說明sql執行失敗了。
fmt.Println("查詢失敗", err)
}
~~~
> 或者
~~~
if db.Take(&food).RecordNotFound() {
fmt.Println("查詢不到數據")
}
~~~
### where
> 語法:`db.Where(query interface{}, args ...interface{})`
~~~
例子1:
//等價于: SELECT * FROM `foods` WHERE (id = '10') LIMIT 1
//這里問號(?), 在執行的時候會被10替代
db.Where("id = ?", 10).Take(&food)
//例子2:
//等價于: SELECT * FROM `foods` WHERE (id in ('1','2','5','6')) LIMIT 1
//args參數傳遞的是數組
db.Where("id in (?)", []int{1,2,5,6}).Take(&food)
//例子3:
//等價于: SELECT * FROM `foods` WHERE (create_time >= '2018-11-06 00:00:00' and create_time <= '2018-11-06 23:59:59')
//這里使用了兩個問號(?)占位符,后面傳遞了兩個參數替換兩個問號。
db.Where("create_time >= ? and create_time <= ?", "2018-11-06 00:00:00", "2018-11-06 23:59:59").Find(&foods)
//例子4:
//等價于: SELECT * FROM `foods` WHERE (title like '%可樂%')
db.Where("title like ?", "%可樂%").Find(&foods)
~~~
### select
> 設置select子句, 指定返回的字段
~~~
//例子1:
//等價于: SELECT id,title FROM `foods` WHERE `foods`.`id` = '1' AND ((id = '1')) LIMIT 1
db.Select("id,title").Where("id = ?", 1).Take(&food)
//這種寫法是直接往Select函數傳遞數組,數組元素代表需要選擇的字段名
db.Select([]string{"id", "title"}).Where("id = ?", 1).Take(&food)
//例子2:
//可以直接書寫聚合語句
//等價于: SELECT count(*) as total FROM `foods`
total := []int{}
//Model函數,用于指定綁定的模型,這里生成了一個Food{}變量。目的是從模型變量里面提取表名,Pluck函數我們沒有直接傳遞綁定表名的結構體變量,gorm庫不知道表名是什么,所以這里需要指定表名
//Pluck函數,主要用于查詢一列值
db.Model(Food{}).Select("count(*) as total").Pluck("total", &total)
fmt.Println(total[0])
~~~
### order
> 設置排序語句,order by子句
~~~
//例子:
//等價于: SELECT * FROM `foods` WHERE (create_time >= '2018-11-06 00:00:00') ORDER BY create_time desc
db.Where("create_time >= ?", "2018-11-06 00:00:00").Order("create_time desc").Find(&foods)
~~~
### limit & Offset
> 設置limit和Offset子句,分頁的時候常用語句
~~~
//等價于: SELECT * FROM `foods` ORDER BY create_time desc LIMIT 10 OFFSET 0
db.Order("create_time desc").Limit(10).Offset(0).Find(&foods)
~~~
### count
> Count函數,直接返回查詢匹配的行數
~~~
//例子:
total := 0
//等價于: SELECT count(*) FROM `foods`
//這里也需要通過model設置模型,讓gorm可以提取模型對應的表名
db.Model(Food{}).Count(&total)
fmt.Println(total)
~~~
### 分組
~~~
//例子:
//統計每個商品分類下面有多少個商品
//定一個Result結構體類型,用來保存查詢結果
type Result struct {
Type int
Total int
}
var results []Result
//等價于: SELECT type, count(*) as total FROM `foods` GROUP BY type HAVING (total > 0)
db.Model(Food{}).Select("type, count(*) as total").Group("type").Having("total > 0").Scan(&results)
//scan類似Find都是用于執行查詢語句,然后把查詢結果賦值給結構體變量,區別在于scan不會從傳遞進來的結構體變量提取表名.
//這里因為我們重新定義了一個結構體用于保存結果,但是這個結構體并沒有綁定foods表,所以這里只能使用scan查詢函數。
~~~
> 提示:Group函數必須搭配Select函數一起使用
### 直接執行sql語句
> 對于復雜的查詢,例如多表連接查詢,我們可以直接編寫sql語句
~~~
sql := "SELECT type, count(*) as total FROM `foods` where create_time > ? GROUP BY type HAVING (total > 0)"
//因為sql語句使用了一個問號(?)作為綁定參數, 所以需要傳遞一個綁定參數(Raw第二個參數).
//Raw函數支持綁定多個參數
db.Raw(sql, "2018-11-06 00:00:00").Scan(&results)
fmt.Println(results)
~~~
- 基礎知識
- 開發環境
- 包名規則
- 包初始化 (init)
- 基礎數據類型
- 基礎類型轉換
- 格式化輸出
- go指針
- 流程控制語句
- 函數定義
- 匿名函數
- 數組和切片
- map集合
- 結構體
- Interface接口
- 日期處理
- 數學計算
- 正則表達式
- 協程 (并發處理)
- channel
- waitgroup
- mutex (鎖機制)
- websocket
- protobuf
- Redis
- 錯誤處理
- 打包程序
- NSQ消息隊列
- 單元測試
- beego
- 安裝入門
- Gin
- 快速入門
- 路由與控制器
- 處理請求參數
- 表單驗證
- 處理響應結果
- 渲染HTML模版
- 訪問靜態文件
- Gin中間件
- Cookie處理
- Session處理
- Gin上傳文件
- swagger
- pprof性能測試
- GORM
- 入門教程
- 模型定義
- 數據庫連接
- 插入數據
- 查詢數據
- 更新數據
- 刪除數據
- 事務處理
- 關聯查詢
- 屬于 (BELONG TO)
- 一對一 (Has One)
- 一對多 (Has Many)
- 多對多 (Many to Many)
- 預加載 (Preloading)
- 錯誤處理
- 第三方常用插件
- viper 讀取配置文件
- zap 高性能日志
- Nginx代理配置
- Goland 快捷鍵