Go ORM的封裝解決方式詳解
背景
去年慢慢開始接觸了Go語言,也在公司寫了幾個Go的生產(chǎn)項目。我是從Java轉(zhuǎn)過來的。(其實也不算轉(zhuǎn),公司用啥,我用啥)在這個過程中,老是想用Java的思維寫Go,在開始的一兩個月,那是邊寫邊吐槽。
丑陋的錯誤處理,沒有流式處理,還竟然沒有泛型,框架生態(tài)鏈不成熟,沒有一家獨大的類似Spring的框架。(其實現(xiàn)在寫了快一年的Go,Go還是挺香的,哈哈)
今天,我來聊一下,我在我在寫Go過程中用的最多orm框架gorm。
Java的orm
寫過Java的基本都知道Mybatis,Mybatis-plus。
在Mybatis-plus中操作單表非常方便,通過QueryWrapper,對于單表的操作非常的絲滑,沒有任何的思維負(fù)擔(dān)。
類似下面這樣:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(User::getUsername,"zhangsan").eq(User::getAge,18);
userMapper.selectList(queryWrapper);
Go的orm
這里的條件查詢都需要開發(fā)手動來拼接字符串,如果項目比較大的話,就會看到漫天飛的SQL字段,維護起來非常麻煩。
var users []*User
sqlResult := db.Where("username = ? and age = ?", "zhangsan", 18).Find(&users)
解決方式
寫了一段時間的Go之后,實在不想每次都寫這些字符串拼接了,于是我給gorm封裝了一個gorm-plus。
這里我使用到了go 1.18的泛型。泛型出了這么久,也該使用上了。
其實就是把Mybatis-plus的那套語法借鑒了一下。(好吧,就是抄他的)
Mybatis-plus對于單表操作提供了非常多的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ù)庫
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)
}
插入語句
user := &User{Username: "zhangsan", Password: "123456", Age: 18, Score: 100, Dept: "A部門"}
result := gplus.Insert(user)
fmt.Println(result.RowsAffected)
查詢語句
根據(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)
對比一下Mybatis-plus寫法基本一致了。
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(User::getUsername,"zhangsan").eq(User::getAge,18);
userMapper.selectList(queryWrapper);
更多操作請查看:
gplus工具
其實上面的寫法還是需要寫數(shù)據(jù)庫的字段名,如果數(shù)據(jù)庫的字段名很多,我們很容易寫錯,導(dǎo)致不必要的bug 產(chǎn)生。
一旦名稱長,非常容易誤寫,而且如果有字段名稱修改的話,還需要全局搜索一個個地修改,比較麻煩。
Go沒有提供類似Java的lambad表達(dá)式或者C#中 nameof 方式直接獲取某個對象的字段名稱的操作,但是我們可以通過生成代碼的方式生成字段名。
所有就有了gplus,它作用就是自動識別結(jié)構(gòu)體,把結(jié)構(gòu)體的字段名生成出來。
下載使用:
go install github.com/acmestack/gorm-plus/cmd/gplus@latest
通過 gplus gen paths=路徑,gplus 會自動識別帶有// +gplus:column=true注釋的結(jié)構(gòu)體,給這個結(jié)構(gòu)體生成字段。
gplus 會在輸入的路徑下面生成 zz_gen.column.go文件。
例如:
在example目錄下創(chuàng)建了了一個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 (自動生成的)
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",
}
其實你自己也可以手寫這個文件,只不過通過工具生成更加方便而已。
有了這個文件,我們的查詢就變成這樣:
q := gplus.NewQuery[User]() q.Eq(UserColumn.Username, "zhangsan").Eq(UserColumn.Age,18) users, resultDb := gplus.SelectList(q) fmt.Println(users,resultDb.RowsAffected)
這樣維護起來就非常方便了。
最后
更多的用法請查看github地址:https://github.com/acmestack/gorm-plus
以上就是Go ORM的封裝解決方式詳解的詳細(xì)內(nèi)容,更多關(guān)于Go ORM封裝的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
golang實現(xiàn)openssl自簽名雙向認(rèn)證的詳細(xì)步驟
這篇文章主要介紹了golang實現(xiàn)openssl自簽名雙向認(rèn)證的詳細(xì)步驟,本文分步驟給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-03-03
golang struct 實現(xiàn) interface的方法
這篇文章主要介紹了golang struct 實現(xiàn) interface的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07
golang框架中跨服務(wù)的最佳通信協(xié)議和工具
在 go 框架中實現(xiàn)跨服務(wù)通信的最佳實踐包括使用 grpc(適用于低延遲高吞吐量)、http 客戶端(適用于 restful api)和消息隊列(適用于異步解耦通信),在選擇通信方式時,應(yīng)考慮服務(wù)交互模式、性能要求和部署環(huán)境等因素2024-06-06

