最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Go語言單元測試中如何解決MySQL存儲依賴問題

 更新時間:2023年07月31日 09:19:01   作者:江湖十年  
MySQL?存儲就是一個非常常見的外部依賴,這篇文章主要來和大家一起探討在?Go?語言中編寫單元測試時,如何解決?MySQL?存儲依賴,需要的可以參考一下

在編寫單元測試的過程中,如果被測試代碼有外部依賴,為了便于測試,我們就要想辦法來解決這些外部依賴問題。在做 Web 開發(fā)時,MySQL 存儲就是一個非常常見的外部依賴,本文就來探討在 Go 語言中編寫單元測試時,如何解決 MySQL 存儲依賴。

HTTP 服務程序示例

假設我們有一個 HTTP 服務程序對外提供服務,代碼如下:

main.go

package main
import (
	"encoding/json"
	"fmt"
	"gorm.io/gorm"
	"io"
	"net/http"
	"strconv"
	"github.com/julienschmidt/httprouter"
	"github.com/jianghushinian/blog-go-example/test/mysql/store"
)
func NewUserHandler(db *gorm.DB) *UserHandler {
	return &UserHandler{
		store: store.NewUserStore(db),
	}
}
type UserHandler struct {
	store store.UserStore
}
func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	...
}
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	...
}
func setupRouter(handler *UserHandler) *httprouter.Router {
	router := httprouter.New()
	router.POST("/users", handler.CreateUser)
	router.GET("/users/:id", handler.GetUser)
	return router
}
func main() {
	mysqlDB, _ := store.NewMySQLDB("localhost", "3306", "user", "password", "test")
	handler := NewUserHandler(mysqlDB)
	router := setupRouter(handler)
	_ = http.ListenAndServe(":8000", router)
}

這個服務監(jiān)聽 8000 端口,分別提供了兩個 HTTP 接口:

POST /users 用來創(chuàng)建用戶。

GET /users/:id 用來獲取指定 ID 對應的用戶信息。

UserHandler 是一個結構體,它依賴外部存儲接口 store.UserStore,這個接口定義如下:

store/store.go

package store
import "gorm.io/gorm"
type UserStore interface {
	Create(user *User) error
	Get(id int) (*User, error)
}
func NewUserStore(db *gorm.DB) UserStore {
	return &userStore{db}
}
type userStore struct {
	db *gorm.DB
}
func (s *userStore) Create(user *User) error {
	return s.db.Create(user).Error
}
func (s *userStore) Get(id int) (*User, error) {
	var user User
	err := s.db.First(&user, id).Error
	return &user, err
}

store.UserStore 定義了兩個方法,分別用來創(chuàng)建、獲取用戶信息。

User 模型定義如下:

store/model.go

type User struct {
	ID   int    `gorm:"id"`
	Name string `gorm:"name"`
}

store.userStore 結構體則實現(xiàn)了 store.UserStore 接口。

store.userStore 結構體又依賴了 GORM 庫的 *gorm.DB 類型,表示一個數(shù)據(jù)庫連接對象。

我們可以使用 NewMySQLDB 建立數(shù)據(jù)庫連接得到 *gorm.DB 對象:

store/mysql.go

func NewMySQLDB(host, port, user, pass, dbname string) (*gorm.DB, error) {
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		user, pass, host, port, dbname)
	return gorm.Open(mysql.Open(dsn), &gorm.Config{})
}

至此,這個 HTTP 服務程序整體邏輯就基本介紹完了。

其目錄結構如下:

$ tree
.
├── go.mod
├── go.sum
├── main.go
└── store
    ├── model.go
    ├── mysql.go
    └── store.go

為了保證業(yè)務的正確性,我們應該對 (*UserHandler).CreateUser(*UserHandler).GetUser 這兩個 Handler 進行單元測試。

這兩個 Handler 定義如下:

func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	w.Header().Set("Content-Type", "application/json")
	body, err := io.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		_, _ = fmt.Fprintf(w, `{"msg":"%s"}`, err.Error())
		return
	}
	defer func() { _ = r.Body.Close() }()
	u := store.User{}
	if err := json.Unmarshal(body, &u); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		_, _ = fmt.Fprintf(w, `{"msg":"%s"}`, err.Error())
		return
	}
	if err := h.store.Create(&u); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		_, _ = fmt.Fprintf(w, `{"msg":"%s"}`, err.Error())
		return
	}
	w.WriteHeader(http.StatusCreated)
}
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	id := ps[0].Value
	uid, _ := strconv.Atoi(id)
	w.Header().Set("Content-Type", "application/json")
	u, err := h.store.Get(uid)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		_, _ = fmt.Fprintf(w, `{"msg":"%s"}`, err.Error())
		return
	}
	_, _ = fmt.Fprintf(w, `{"id":%d,"name":"%s"}`, u.ID, u.Name)
}

不過,由于文章篇幅所限,我這里僅以測試 (*UserHandler).GetUser 方法為例,演示如何在測試過程中解決 MySQL 依賴問題,對 (*UserHandler).CreateUser 方法的測試就當做作業(yè)留給你自己來完成了(當然,你也可以到我的 GitHub 上查看我的實現(xiàn))。

Fake 測試

我們要為 (*UserHandler).GetUser 方法編寫單元測試,首先就要分析下這個方法的外部依賴。

func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	id := ps[0].Value
	uid, _ := strconv.Atoi(id)
	w.Header().Set("Content-Type", "application/json")
	u, err := h.store.Get(uid)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		_, _ = fmt.Fprintf(w, `{"msg":"%s"}`, err.Error())
		return
	}
	_, _ = fmt.Fprintf(w, `{"id":%d,"name":"%s"}`, u.ID, u.Name)
}

UserHandler 結構本身依賴了 store.UserStore,這是一個接口,定義了創(chuàng)建和獲取用戶信息的兩個方法。

我們使用實現(xiàn)了 store.UserStore 接口的 store.userStore 結構體來初始化 UserHandler

func NewUserHandler(db *gorm.DB) *UserHandler {
	return &UserHandler{
		store: store.NewUserStore(db),
	}
}
func NewUserStore(db *gorm.DB) UserStore {
	return &userStore{db}
}

store.userStore 結構體會使用 GORM 來完成對 MySQL 數(shù)據(jù)庫的操作。所以,我們分析出 GetUser 方法的第一個外部依賴實際上就是 MySQL 存儲。

GetUser 方法還接收三個參數(shù),它們都屬于 HTTP 網(wǎng)絡相關的外部依賴,你可以在我的另一篇文章《在 Go 語言單元測試中如何解決 HTTP 網(wǎng)絡依賴問題》中找到解決方案,就不在本文中進行講解了。

所以,我們現(xiàn)在重點要關注的就只有一個問題,如何解決 MySQL 存儲依賴。

我們來整理下 MySQL 外部依賴的程序調(diào)用鏈:

可以發(fā)現(xiàn),store.UserStore 接口是 UserHandlerstore.userStore 結構體建立連接的橋梁,我們可以將它作為突破口,實現(xiàn)一個 Fake object,來替換 store.userStore 結構體。

所謂 Fake object,其實就是我們同樣要定義一個結構體,并實現(xiàn) CreateGet 兩個方法,以此來實現(xiàn) store.UserStore 接口。

type fakeUserStore struct{}
func (f *fakeUserStore) Create(user *store.User) error {
	return nil
}
func (f *fakeUserStore) Get(id int) (*store.User, error) {
	return &store.User{ID: id, Name: "test"}, nil
}

store.userStore 結構體不同,fakeUserStore 并不依賴 *gorm.DB,也就不涉及 MySQL 數(shù)據(jù)庫操作了,這樣就解決了 MySQL 外部存儲依賴。

(*fakeUserStore).Create 方法沒做任何操作,直接返回 nil(*fakeUserStore).Get 方法則根據(jù)傳進來的 id 返回固定的 User 信息。這也是 Fake object 的特點,為真實對象實現(xiàn)一個簡化版本。

這樣,我們在編寫測試代碼時,只需要取代 store.userStore 結構體,使用 fakeUserStore 來實例化 UserHandler,就可以避免與 MySQL 數(shù)據(jù)庫打交道了。

handler := &UserHandler{store: &fakeUserStore{}}

(*UserHandler).GetUser 方法編寫的單元測試完整代碼如下:

func TestUserHandler_GetUser_by_fake(t *testing.T) {
	handler := &UserHandler{store: &fakeUserStore{}}
	router := setupRouter(handler)
	w := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/users/1", nil)
	router.ServeHTTP(w, req)
	assert.Equal(t, 200, w.Code)
	assert.Equal(t, "application/json", w.Header().Get("Content-Type"))
	assert.Equal(t, `{"id":1,"name":"test"}`, w.Body.String())
}

現(xiàn)在被測試的 (*UserHandler).GetUser 方法中通過 h.store.Get(uid) 從數(shù)據(jù)庫中獲取用戶信息時,就不用再去查詢 MySQL 了,而是由 (*fakeUserStore).Get 方法直接返回 Fake 數(shù)據(jù)。

使用 go test 來執(zhí)行測試函數(shù):

$ go test -v -run="TestUserHandler_GetUser_by_fake"
=== RUN   TestUserHandler_GetUser_by_fake
--- PASS: TestUserHandler_GetUser_by_fake (0.00s)
PASS
ok      github.com/jianghushinian/blog-go-example/test/mysql    0.465s

測試通過。

可以發(fā)現(xiàn),使用 Fake 測試來解決 MySQL 外部依賴還是比較簡單的,我們僅需要參考 store.userStore 實現(xiàn)一個簡化版本的 fakeUserStore,然后在測試過程中,使用簡化版本的 fakeUserStore 對象替換掉 store.userStore 即可。

Mock 測試

前文中,我們使用 fakeUserStore 來替換 store.userStore,以此來接口 MySQL 依賴問題。

不過,這種使用 Fake object 來解決外部依賴的方式存在兩個較為常見的弊端:

一個是使用 Fake object 需要手動編寫大量代碼,這里的 store.UserStore 接口僅定義了兩個方法還好,但一個線上的復雜業(yè)務,可能有幾十個接口,每個接口又有幾十個方法,此時如果還是手動來編寫這些代碼,需要消耗大量時間。

另一個是 Fake object 返回結果比較固定,如果想測試其他情況,比如查詢的 User 不存在,需要報錯的情況,就得在 (*fakeUserStore).Get 方法中編寫更多的邏輯,這增加了實現(xiàn) Fake object 的復雜度。

那么有沒有一種替代方案,來彌補 Fake object 的這兩個弊端呢?

答案是使用 Mock 測試。

Mock 和 Fake 類似,本質上都是使用一個對象,去替代另一個對象。Fake 測試是實現(xiàn)了一個真實對象(store.userStore)的簡化版本(fakeUserStore),Mock 測試則是使用模擬對象來斷言真實對象被調(diào)用時的輸入符合預期,然后通過模擬對象返回指定輸出。

在 Go 中,我們可以使用 gomock 來實現(xiàn) Mock 測試。

gomock 項目起源于 Google 的 golang/mock 倉庫。不幸的是,谷歌不再維護這個項目了。幸運的是,這個項目由 Uber fork 了一份,并繼續(xù)維護。

gomock 包含兩個部分:gomock 包和 mockgen 命令行工具。gomock 包用來完成對被 Mock 對象的生命周期管理,mockgen 工具則用來自動生成 Mock 代碼。

可以通過如下方式來安裝 gomock 包和 mockgen 工具:

$ go get go.uber.org/mock/gomock@latest
$ go install go.uber.org/mock/mockgen@latest

注意:在項目根目錄下通過 go get 命令獲取 gomock 包后,不要急著執(zhí)行 go mod tidy,因為現(xiàn)在 gomock 包屬于 indirect 依賴,還沒有被使用。當通過 mockgen 工具生成了 Mock 代碼以后,再來執(zhí)行 go mod tidygo.mod 文件中才不會丟失 gomock 依賴。

要想使用 gomock 來模擬 store.UserStore 接口的實現(xiàn),我們先要使用 mockgen 工具來生成 Mock 代碼:

 $ mockgen -source store/store.go -destination store/mocks/gomock.go -package mocks

-source 參數(shù)指明需要 Mock 的接口文件路徑,即 store.UserStore 接口所在文件。

-destination 參數(shù)指明生成的 Mock 文件路徑。

-package 參數(shù)指明生成的 Mock 文件包名。

在項目根目錄下執(zhí)行 mockgen 命令,即可生成 Mock 文件:

// Code generated by MockGen. DO NOT EDIT.
// Source: store/store.go
// Package mocks is a generated GoMock package.
package mocks
import (
	reflect "reflect"
	store "github.com/jianghushinian/blog-go-example/test/mysql/store"
	gomock "go.uber.org/mock/gomock"
)
// MockUserStore is a mock of UserStore interface.
type MockUserStore struct {
	ctrl     *gomock.Controller
	recorder *MockUserStoreMockRecorder
}
// MockUserStoreMockRecorder is the mock recorder for MockUserStore.
type MockUserStoreMockRecorder struct {
	mock *MockUserStore
}
// NewMockUserStore creates a new mock instance.
func NewMockUserStore(ctrl *gomock.Controller) *MockUserStore {
	mock := &MockUserStore{ctrl: ctrl}
	mock.recorder = &MockUserStoreMockRecorder{mock}
	return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockUserStore) EXPECT() *MockUserStoreMockRecorder {
	return m.recorder
}
// Create mocks base method.
func (m *MockUserStore) Create(user *store.User) error {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "Create", user)
	ret0, _ := ret[0].(error)
	return ret0
}
// Create indicates an expected call of Create.
func (mr *MockUserStoreMockRecorder) Create(user interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockUserStore)(nil).Create), user)
}
// Get mocks base method.
func (m *MockUserStore) Get(id int) (*store.User, error) {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "Get", id)
	ret0, _ := ret[0].(*store.User)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}
// Get indicates an expected call of Get.
func (mr *MockUserStoreMockRecorder) Get(id interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockUserStore)(nil).Get), id)
}

提示:生成的 mocks 包代碼你無需全部看懂,僅知道它大概生成了什么內(nèi)容,如何使用即可。

可以發(fā)現(xiàn),mockgen 為我們生成了 mocks.MockUserStore 結構體,并且實現(xiàn)了 Create、Get 兩個方法,即實現(xiàn)了 store.UserStore 接口。

現(xiàn)在,我們就可以使用生成的 Mock 對象來編寫單元測試代碼了:

func TestUserHandler_GetUser_by_mock(t *testing.T) {
	ctrl := gomock.NewController(t)
	// 斷言 mockUserStore.Get 方法會被調(diào)用
	defer ctrl.Finish()
	mockUserStore := mocks.NewMockUserStore(ctrl)
	mockUserStore.EXPECT().Get(2).Return(&store.User{
		ID:   2,
		Name: "user2",
	}, nil)
	handler := &UserHandler{store: mockUserStore}
	router := setupRouter(handler)
	w := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/users/2", nil)
	router.ServeHTTP(w, req)
	assert.Equal(t, 200, w.Code)
	assert.Equal(t, "application/json", w.Header().Get("Content-Type"))
	assert.Equal(t, `{"id":2,"name":"user2"}`, w.Body.String())
}

gomock.NewController(t) 用來創(chuàng)建一個 Mock 控制器,該對象可以控制整個 Mock 生命周期。

ctrl.Finish() 用來斷言 Mock 對象使用 EXPECT() 方法設置的期待執(zhí)行方法會被調(diào)用,一般使用 defer 語句來調(diào)用,防止最后忘記。不過,如果你使用的 Go 版本大于 1.14,則可以不必顯式調(diào)用 ctrl.Finish()

mocks.NewMockUserStore(ctrl) 使用 Mock 控制器創(chuàng)建了 *mocks.MockUserStore 對象,有了它,我們就可以模擬調(diào)用 store.UserStore 接口對應方法的邏輯了:

mockUserStore.EXPECT().Get(2).Return(&store.User{
    ID:   2,
    Name: "user2",
}, nil)

mockUserStore 對象就相當于我們前文中實現(xiàn)的 fakeUserStore。

Mock 對象的 EXPECT() 方法用來設置預期被調(diào)用的方法,以及被調(diào)用方法所期望的輸入,它支持鏈式調(diào)用,.Get(2) 表示期望在測試中調(diào)用 Mock 對象 mockUserStoreGet 方法時,輸入?yún)?shù)是 2,Return 方法用來設置輸出,即返回值內(nèi)容。

這就相當于,我們實現(xiàn)了 fakeUserStoreGet 方法。

我們可以使用 mockUserStore 來實例化 UserHandler 對象。

req 請求中,我們設置請求的用戶 ID 值為 2,即 mockUserStore 對象斷言中的參數(shù),二者參數(shù)匹配,Mock 對象才能生效。

單元測試最后,斷言了返回結果為 {"id":2,"name":"user2"},即 mockUserStore 對象期望的返回結果。

現(xiàn)在我們就可以測試 (*UserHandler).GetUser 方法了。

使用 go test 來執(zhí)行測試函數(shù):

$ go test -v -run="TestUserHandler_GetUser_by_mock"
=== RUN   TestUserHandler_GetUser_by_mock
--- PASS: TestUserHandler_GetUser_by_mock (0.00s)
PASS
ok      github.com/jianghushinian/blog-go-example/test/mysql    0.220s

測試通過。

使用 Mock 測試來解決 MySQL 外部依賴問題,我們無需手動編寫 Mock 對象的代碼,可以使用 mockgen 工具為我們自動生成,簡化了 Fake 測試中編寫 fakeUserStore 的過程。

并且,如果想要測試其他情況,僅需要再次使用 Mock 對象的 EXPECT() 方法來設置 Get 方法的期望輸入和輸出即可。

比如設置預期查詢 ID 為 3 的用戶信息時,返回 user not found 錯誤:

mockUserStore.EXPECT().Get(3).Return(nil, errors.New("user not found"))

Mock 測試更方便我們測試不同業(yè)務場景。

gomock 更多用法

gomock 還有一些使用技巧值得分享。

mockgen

前文中,我們使用 mockgen 通過指定源碼文件形式生成了 Mock 代碼:

$ mockgen -source store/store.go -destination store/mocks/gomock.go -package mocks

mockgen 工具還支持通過反射模式來生成 Mock 代碼:

$ mockgen -package mocks -destination store/mocks/gomock.go github.com/jianghushinian/blog-go-example/test/mysql/store UserStore

命令最后的兩個參數(shù)分別代表需要生成 Mock 代碼的包的導入路徑和逗號分隔的接口列表。

執(zhí)行以上命令同樣能夠成功生成 Mock 代碼。

此外,我們還可以將 mockgen 命令寫到 Go 文件中,然后使用 Go generate 工具來生成 Mock 代碼:

store/generate.go

package store
//go:generate mockgen -package mocks -destination ./mocks/gomock.go . UserStore

這次我們的 mockgen 命令又有所不同,包的導入路徑僅為一個 .,表示當前目錄,這也是被支持的。

這時候,我們只需要在項目根目錄下執(zhí)行 go generate ./... 命令即可生成 Mock 代碼。./... 表示查找項目下全部文件,go generate 會自動找到帶有 //go:generate 注釋的命令并執(zhí)行。

如果我們有多個源碼文件要生成 Mock 代碼,go generate 方式就非常合適,僅需要在 Go 文件中分多行依次寫出 mockgen 命令即可使用一條命令一次全部生成。

gomock

前文中,我們使用了 Mock 對象 mockUserStoreEXPECT() 方法來設置 Get 方法所期待的輸入和輸出。

mockUserStore.EXPECT().Get(2).Return(&store.User{
    ID:   2,
    Name: "user2",
}, nil)

有時候,EXPECT() 所作用的方法可能存在多個參數(shù),且有些參數(shù)不容易模擬,比如最常見的 context.Context 參數(shù),針對這些情況,gomock 提供了更多的參數(shù)匹配方法:

gomock.Any() 表示匹配任意參數(shù),適合參數(shù)模擬困難的情況。

gomock.Eq(x) 表示匹配與 x 相等的參數(shù)。

gomock.Not(x) 表示匹配與 x 不想等的參數(shù)。

gomock.Nil() 表示匹配 nil 參數(shù)。

gomock.Len(i) 表示匹配長度為 i 的參數(shù)。

gomock.All(ms) 表示傳入的所有參數(shù)都想等才能匹配。

以上這些參數(shù)匹配方法都可以像如下這樣使用:

mockUserStore.EXPECT().Get(gomock.Eq(2)).Return(&store.User{
    ID:   2,
    Name: "user2",
}, nil)

此外,我們可以約束 EXPECT() 所作用方法的執(zhí)行次數(shù):

.Return(xxx).Times(2) // 預期方法會被調(diào)用 2 次
.Return(xxx).MaxTimes(2) // 預期方法最多執(zhí)行 2 次
.Return(xxx).MinTimes(2) // 預期方法至少執(zhí)行 2 次
.Return(xxx).AnyTimes() // 預期方法執(zhí)行任意次都能匹配

還可以約束 EXPECT() 所作用方法的執(zhí)行順序:

.Return(xxx).After(preReq) // 當前預期方法在 preReq 預期方法執(zhí)行完成之后執(zhí)行

以上便是我認為 gomock 中比較常用的功能講解,更多功能可參考官方文檔。

總結

本文向大家介紹了在 Go 中編寫單元測試時,如何解決 MySQL 外部依賴的問題。

我們分別使用了 Fake object 和 Mock 兩種方式,來替換原有的外部依賴。

Web 服務的代碼不是隨意設計的,有意將 UserHandler 依賴的類型設為 store.UserStore 接口,而不是 store.userStore 結構體,是為了解耦。通過使用接口,解決了 UserHandlerstore.userStore 結構體強綁定的問題,這就給我們使用 fakeUserStoremockUserStore 來替代 store.userStore 創(chuàng)造了機會。

可以發(fā)現(xiàn),本文介紹的兩種方法其實不僅能夠用于解決 MySQL 外部依賴問題。任何使用接口編寫的代碼,在測試時都可以使用這兩種方式來替換依賴。這就是 Go 面向接口編程的好處。

以上就是詳解Go語言單元測試中如何解決MySQL存儲依賴問題的詳細內(nèi)容,更多關于Go單元測試解決MySQL存儲依賴的資料請關注腳本之家其它相關文章!

相關文章

  • go并發(fā)編程sync.Cond使用場景及實現(xiàn)原理

    go并發(fā)編程sync.Cond使用場景及實現(xiàn)原理

    這篇文章主要為大家介紹了go并發(fā)編程sync.Cond使用場景及實現(xiàn)原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • Go語言實現(xiàn)Snowflake雪花算法

    Go語言實現(xiàn)Snowflake雪花算法

    雪花算法產(chǎn)生的背景當然是twitter高并發(fā)環(huán)境下對唯一ID生成的需求,得益于twitter內(nèi)部牛的技術,雪花算法能夠流傳于至今并且被廣泛使用,本文就詳細的介紹一下,感興趣的可以了解一下
    2021-06-06
  • 提升Go語言開發(fā)效率的小技巧實例(GO語言語法糖)匯總

    提升Go語言開發(fā)效率的小技巧實例(GO語言語法糖)匯總

    這篇文章主要介紹了提升Go語言開發(fā)效率的小技巧匯總,也就是Go語言的語法糖,掌握好這些可以提高我們的開發(fā)效率,需要的朋友可以參考下
    2022-11-11
  • 詳解go如何使用xorm在執(zhí)行前改寫?SQL

    詳解go如何使用xorm在執(zhí)行前改寫?SQL

    這篇文章主要為大家介紹了詳解go如何使用xorm在執(zhí)行前改寫SQL的實現(xiàn)過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • Goland IDEA項目多開設置方式

    Goland IDEA項目多開設置方式

    這篇文章主要介紹了Goland IDEA項目多開設置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 詳解Go語言中io/ioutil工具的使用

    詳解Go語言中io/ioutil工具的使用

    這篇文章主要為大家詳細介紹了Go語言中io/ioutil工具的使用,從而簡化文件操作。文中是示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2022-05-05
  • Go語言配置數(shù)據(jù)庫連接池的實現(xiàn)

    Go語言配置數(shù)據(jù)庫連接池的實現(xiàn)

    本文內(nèi)容我們將解釋連接池背后是如何工作的,并探索如何配置數(shù)據(jù)庫能改變或優(yōu)化其性能。文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • 淺析Go中fasthttp與net/http的性能對比及應用

    淺析Go中fasthttp與net/http的性能對比及應用

    這篇文章主要為大家詳細介紹了Golang中fasthttp的底層實現(xiàn)以及與net/http的區(qū)別,下面就跟隨小編一起來看看fasthttp到底是如何做到性能如此之快的吧
    2024-03-03
  • Go語言中兩個比較流行的緩存庫使用示例

    Go語言中兩個比較流行的緩存庫使用示例

    緩存是計算機科學中的一個重要概念,設想某個組件需要訪問外部資源,它向外部源請求資源,接收并使用資源,這些步驟都需要花費時間,下面這篇文章主要給大家介紹了關于Go語言中兩個比較流行的緩存庫使用的相關資料,需要的朋友可以參考下
    2024-04-04
  • golang如何修改json文件內(nèi)容的方法示例

    golang如何修改json文件內(nèi)容的方法示例

    這篇文章主要介紹了golang如何修改json文件內(nèi)容的方法示例,使用一個例子說明golang如何訪問和修改json文件,有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-10-10

最新評論

安仁县| 分宜县| 罗甸县| 巴马| 博乐市| 阿拉尔市| 普定县| 正定县| 梁平县| 红安县| 余庆县| 深水埗区| 宁国市| 噶尔县| 舒城县| 八宿县| 博湖县| 滦南县| 行唐县| 迁安市| 永昌县| 木里| 台东市| 西乌| 龙山县| 延津县| 江西省| 武穴市| 山西省| 深圳市| 顺平县| 兴文县| 靖宇县| 独山县| 探索| 东乡| 宁波市| 莒南县| 洪雅县| 逊克县| 随州市|