【go商城】gin+gorm實現CRUD

gorm是什么?

ORM-Object-Relationl Mapping,即對象關系映射,這里的Relationl指的是關系型數據庫
它的作用是在關系型數據庫和對象之間作一個映射,這樣,我們在具體的操作數據庫的時候,就不需要再去和復雜的SQL語句打交道,只要像平時操作對象一樣操作它就可以了
GORM就是go語言實現的一個ORM庫,特點:

  • 全特性 ORM (幾乎包含所有特性)
  • 模型關聯 (一對一, 一對多,一對多(反向), 多對多, 多態關聯)
  • 鉤子 (Before/After Create/Save/Update/Delete/Find)
  • 預加載
  • 事務
  • 復合主鍵
  • SQL 構造器
  • 自動遷移
  • 日志
  • 基于GORM回調編寫可擴展插件
  • 全特性測試覆蓋
  • 開發者友好

GORM之簡單CRUD

增加(Create)

user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}

db.NewRecord(user) // => 返回 `true` ,因為主鍵為空

db.Create(&user)

db.NewRecord(user) // => 在 `user` 之后創建返回 `false`

檢索(Retrieve)

// 獲取第一條記錄,按主鍵排序
db.First(&user)
//// SELECT * FROM users ORDER BY id LIMIT 1;

// 獲取一條記錄,不指定排序
db.Take(&user)
//// SELECT * FROM users LIMIT 1;

// 獲取最后一條記錄,按主鍵排序
db.Last(&user)
//// SELECT * FROM users ORDER BY id DESC LIMIT 1;

// 獲取所有的記錄
db.Find(&users)
//// SELECT * FROM users;

// 通過主鍵進行查詢 (僅適用于主鍵是數字類型)
db.First(&user, 10)
//// SELECT * FROM users WHERE id = 10;

更新(Update)

db.First(&user)

user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)

// 如果單個屬性被更改了,更新它
db.Model(&user).Update("name", "hello")
//// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;

// 使用組合條件更新單個屬性
db.Model(&user).Where("active = ?", true).Update("name", "hello")
//// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;

刪除(Delete)

// 刪除一條存在的記錄
db.Delete(&email)
//// DELETE from emails where id=10;

// 為刪除 SQL 語句添加額外選項
db.Set("gorm:delete_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Delete(&email)
//// DELETE from emails where id=10 OPTION (OPTIMIZE FOR UNKNOWN);

如果模型中有 DeletedAt 字段,它將自動擁有軟刪除的能力!當執行刪除操作時,數據并不會永久的從數據庫中刪除,而是將 DeletedAt 的值更新為當前時間。
具體的使用可查看gorm 官方文檔

項目中聲明全局GVA_DB

在項目中我們定義一個全局的GVA_DB,方便使用時調用

// global.go
var (
    GVA_DB     *gorm.DB
    )

后續我們在需要查詢數據庫時便可直接通過global.GVA_DB使用
比如創建商品信息:
我們先通過查詢分類是否存在,然后再創建商品

func (m *ManageGoodsInfoService) CreateMallGoodsInfo(req manageReq.GoodsInfoAddParam) (err error) {
    var goodsCategory manage.MallGoodsCategory
    err = global.GVA_DB.Where("category_id=?  AND is_deleted=0", req.GoodsCategoryId).First(&goodsCategory).Error
    if goodsCategory.CategoryLevel != enum.LevelThree.Code() {
        return errors.New("分類數據異常")
    }
    if !errors.Is(global.GVA_DB.Where("goods_name=? AND goods_category_id=?", req.GoodsName, req.GoodsCategoryId).First(&manage.MallGoodsInfo{}).Error, gorm.ErrRecordNotFound) {
        return errors.New("已存在相同的商品信息")
    }
......
    err = global.GVA_DB.Create(&goodsInfo).Error
    return err
}

通過gorm的鏈式操作可以很方便的進行crud操作

分頁查詢

分頁查詢是項目中經常使用到的功能,當指定條件查詢的數據量過大時,如果我們將數據一次性返回,會對數據庫造成較大的負荷,同時降低接口的性能,通常我們會使用分頁查詢的方式讓數據進行分段展示,從而保障接口的性能。在gorm中我們實用Offset,和Count來實現分頁

Offset 指定在開始返回記錄之前要跳過的記錄數。

db.Offset(3).Find(&users)
//// SELECT * FROM users OFFSET 3;
// 用 -1 取消 OFFSET 限制條件
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
//// SELECT * FROM users OFFSET 10; (users1)
//// SELECT * FROM users; (users2)

Count 獲取模型記錄數。注意: 在查詢鏈中使用 Count 時,必須放在最后一個位置,因為它會覆蓋 SELECT 查詢條件。

db.Where("name = ?", "jinzhu").Or("name = ?", "jinzhu >2").Find(&users).Count(&count)
//// SELECT * from USERS WHERE name = 'jinzhu' OR name = >'jinzhu 2'; (users)
//// SELECT count(*) FROM users WHERE name = 'jinzhu' OR >name = 'jinzhu 2'; 

我們通過前端的傳遞過來的分頁數據進行查詢

func (m *ManageGoodsInfoService) GetMallGoodsInfoInfoList(info manageReq.MallGoodsInfoSearch, goodsName string, goodsSellStatus string) (err error, list interface{}, total int64) {
    limit := info.PageSize
    offset := info.PageSize * (info.PageNumber - 1)
    // 創建db
    db := global.GVA_DB.Model(&manage.MallGoodsInfo{})
    var mallGoodsInfos []manage.MallGoodsInfo
    // 如果有條件搜索 下方會自動創建搜索語句
    err = db.Count(&total).Error
    if err != nil {
        return
    }
    if goodsName != "" {
        db.Where("goods_name =?", goodsName)
    }
    if goodsSellStatus != "" {
        db.Where("goods_sell_status =?", goodsSellStatus)
    }
    err = db.Limit(limit).Offset(offset).Order("goods_id desc").Find(&mallGoodsInfos).Error
    return err, mallGoodsInfos, total
}

總結

該商城作為gin的學習項目,沒有很復雜的邏輯,所有業務邏輯均通過Mysql實現。包括后面將要介紹的登錄態,也是如此。
所有代碼已上傳github,有興趣的可以訪問https://github.com/newbee-ltd/newbee-mall-api-go/,如果有更好的建議也歡迎提交issure,pr

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容