Go ORM的封裝解決方式詳解
背景
去年慢慢開(kāi)始接觸了Go語(yǔ)言,也在公司寫(xiě)了幾個(gè)Go的生產(chǎn)項(xiàng)目。我是從Java轉(zhuǎn)過(guò)來(lái)的。(其實(shí)也不算轉(zhuǎn),公司用啥,我用啥)在這個(gè)過(guò)程中,老是想用Java的思維寫(xiě)Go,在開(kāi)始的一兩個(gè)月,那是邊寫(xiě)邊吐槽。
丑陋的錯(cuò)誤處理,沒(méi)有流式處理,還竟然沒(méi)有泛型,框架生態(tài)鏈不成熟,沒(méi)有一家獨(dú)大的類似Spring的框架。(其實(shí)現(xiàn)在寫(xiě)了快一年的Go,Go還是挺香的,哈哈)
今天,我來(lái)聊一下,我在我在寫(xiě)Go過(guò)程中用的最多orm框架gorm。
Java的orm
寫(xiě)過(guò)Java的基本都知道Mybatis,Mybatis-plus。
在Mybatis-plus中操作單表非常方便,通過(guò)QueryWrapper,對(duì)于單表的操作非常的絲滑,沒(méi)有任何的思維負(fù)擔(dān)。
類似下面這樣:
QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.lambda().eq(User::getUsername,"zhangsan").eq(User::getAge,18); userMapper.selectList(queryWrapper);
Go的orm
這里的條件查詢都需要開(kāi)發(fā)手動(dòng)來(lái)拼接字符串,如果項(xiàng)目比較大的話,就會(huì)看到漫天飛的SQL字段,維護(hù)起來(lái)非常麻煩。
var users []*User sqlResult := db.Where("username = ? and age = ?", "zhangsan", 18).Find(&users)
解決方式
寫(xiě)了一段時(shí)間的Go之后,實(shí)在不想每次都寫(xiě)這些字符串拼接了,于是我給gorm封裝了一個(gè)gorm-plus。
這里我使用到了go 1.18的泛型。泛型出了這么久,也該使用上了。
其實(shí)就是把Mybatis-plus的那套語(yǔ)法借鑒了一下。(好吧,就是抄他的)
Mybatis-plus對(duì)于單表操作提供了非常多的CRUD操作。
我給gorm-plus 也提供了類似的操作
下面是具體用法
下載:
go get github.com/acmestack/gorm-plus
初始化sql
DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `id` int(0) NOT NULL AUTO_INCREMENT, `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `age` int(0) NULL DEFAULT NULL, `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `score` int(0) NULL DEFAULT NULL, `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `dept` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `created_at` datetime(0) NULL DEFAULT NULL, `updated_at` datetime(0) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;
連接數(shù)據(jù)庫(kù)
var GormDb *gorm.DB func init() { dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local" var err error GormDb, err = gorm.Open(mysql.Open(dsn), &gorm.Config{ Logger: logger.Default.LogMode(logger.Info), }) if err != nil { log.Fatalln(err) } gplus.Init(GormDb) }
插入語(yǔ)句
user := &User{Username: "zhangsan", Password: "123456", Age: 18, Score: 100, Dept: "A部門"} result := gplus.Insert(user) fmt.Println(result.RowsAffected)
查詢語(yǔ)句
根據(jù)id查詢:
注意這里需要傳入泛型User
user, resultDb := gplus.SelectById[User](1) fmt.Println(user, resultDb.RowsAffected)
根據(jù)ids查詢:
var ids = []int{1,2} users, resultDb := gplus.SelectByIds[User](ids) fmt.Println(users, resultDb.RowsAffected)
條件查詢:
q := gplus.NewQuery[User]() q.Eq("username", "zhangsan").Eq("age",18) users, resultDb := gplus.SelectList(q) fmt.Println(users,resultDb.RowsAffected)
對(duì)比一下Mybatis-plus寫(xiě)法基本一致了。
QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.lambda().eq(User::getUsername,"zhangsan").eq(User::getAge,18); userMapper.selectList(queryWrapper);
更多操作請(qǐng)查看:
gplus工具
其實(shí)上面的寫(xiě)法還是需要寫(xiě)數(shù)據(jù)庫(kù)的字段名,如果數(shù)據(jù)庫(kù)的字段名很多,我們很容易寫(xiě)錯(cuò),導(dǎo)致不必要的bug 產(chǎn)生。
一旦名稱長(zhǎng),非常容易誤寫(xiě),而且如果有字段名稱修改的話,還需要全局搜索一個(gè)個(gè)地修改,比較麻煩。
Go沒(méi)有提供類似Java的lambad表達(dá)式或者C#中 nameof
方式直接獲取某個(gè)對(duì)象的字段名稱的操作,但是我們可以通過(guò)生成代碼的方式生成字段名。
所有就有了gplus,它作用就是自動(dòng)識(shí)別結(jié)構(gòu)體,把結(jié)構(gòu)體的字段名生成出來(lái)。
下載使用:
go install github.com/acmestack/gorm-plus/cmd/gplus@latest
通過(guò) gplus gen paths=路徑
,gplus 會(huì)自動(dòng)識(shí)別帶有// +gplus:column=true
注釋的結(jié)構(gòu)體,給這個(gè)結(jié)構(gòu)體生成字段。
gplus 會(huì)在輸入的路徑下面生成 zz_gen.column.go
文件。
例如:
在example目錄下創(chuàng)建了了一個(gè)users.go 目錄,執(zhí)行 gplus gen paths=./eample
users.go
// +gplus:column=true type User struct { ID int64 Username string `gorm:"column:username"` Password string Address string Age int Phone string Score int Dept string CreatedAt time.Time UpdatedAt time.Time }
zz_gen.column.go (自動(dòng)生成的)
var UserColumn = struct { ID string Username string Password string Address string Age string Phone string Score string Dept string CreatedAt string UpdatedAt string }{ ID: "id", Username: "username", Password: "password", Address: "address", Age: "age", Phone: "phone", Score: "score", Dept: "dept", CreatedAt: "created_at", UpdatedAt: "updated_at", }
其實(shí)你自己也可以手寫(xiě)這個(gè)文件,只不過(guò)通過(guò)工具生成更加方便而已。
有了這個(gè)文件,我們的查詢就變成這樣:
q := gplus.NewQuery[User]() q.Eq(UserColumn.Username, "zhangsan").Eq(UserColumn.Age,18) users, resultDb := gplus.SelectList(q) fmt.Println(users,resultDb.RowsAffected)
這樣維護(hù)起來(lái)就非常方便了。
最后
更多的用法請(qǐng)查看github地址:https://github.com/acmestack/gorm-plus
以上就是Go ORM的封裝解決方式詳解的詳細(xì)內(nèi)容,更多關(guān)于Go ORM封裝的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- golang http請(qǐng)求封裝代碼
- 利用golang實(shí)現(xiàn)封裝trycatch異常處理實(shí)例代碼
- Go語(yǔ)言Zap庫(kù)Logger的定制化和封裝使用詳解
- Go語(yǔ)言開(kāi)發(fā)redis封裝及簡(jiǎn)單使用詳解
- golang?db事務(wù)的統(tǒng)一封裝的實(shí)現(xiàn)
- 一文教你如何封裝安全的go
- GoLang基于zap日志庫(kù)的封裝過(guò)程詳解
- Golang http請(qǐng)求封裝的代碼示例
- 簡(jiǎn)單高效!Go語(yǔ)言封裝二級(jí)認(rèn)證功能實(shí)現(xiàn)
- 高效封禁:利用Go封裝功能,提升封禁操作效率
相關(guān)文章
go使用net/url包來(lái)解析URL提取主機(jī)部分
這篇文章主要為大家介紹了go使用net/url包來(lái)解析URL提取主機(jī)部分實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01使用Golang獲取音視頻時(shí)長(zhǎng)信息的示例代碼
這篇文章主要介紹了如何使用Golang獲取音視頻時(shí)長(zhǎng)信息,文中通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-03-03golang實(shí)現(xiàn)openssl自簽名雙向認(rèn)證的詳細(xì)步驟
這篇文章主要介紹了golang實(shí)現(xiàn)openssl自簽名雙向認(rèn)證的詳細(xì)步驟,本文分步驟給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-03-03golang struct 實(shí)現(xiàn) interface的方法
這篇文章主要介紹了golang struct 實(shí)現(xiàn) interface的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07Go語(yǔ)言Grpc?Stream的實(shí)現(xiàn)
本文主要介紹了Go語(yǔ)言Grpc?Stream的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06GoLang BoltDB數(shù)據(jù)庫(kù)詳解
這篇文章主要介紹了GoLang BoltDB數(shù)據(jù)庫(kù),boltdb是使用Go語(yǔ)言編寫(xiě)的開(kāi)源的鍵值對(duì)數(shù)據(jù)庫(kù),boltdb存儲(chǔ)數(shù)據(jù)時(shí) key和value都要求是字節(jié)數(shù)據(jù),此處需要使用到 序列化和反序列化2023-02-02golang框架中跨服務(wù)的最佳通信協(xié)議和工具
在 go 框架中實(shí)現(xiàn)跨服務(wù)通信的最佳實(shí)踐包括使用 grpc(適用于低延遲高吞吐量)、http 客戶端(適用于 restful api)和消息隊(duì)列(適用于異步解耦通信),在選擇通信方式時(shí),應(yīng)考慮服務(wù)交互模式、性能要求和部署環(huán)境等因素2024-06-06使用Golang實(shí)現(xiàn)Sm2加解密的代碼詳解
本文主要介紹了Go語(yǔ)言實(shí)現(xiàn)Sm2加解密的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03