Golang+Docker+PostgreSQL+Gin最佳實踐(實現銀行交易項目)

2021-12-21 Go鍵盤俠

前言

此項目是實現一個模擬銀行轉帳交易系統,使用技術棧包括但不限於:Golang、Docker、PostgreSQL、Gin,主要是用來學習練手,熟悉並鞏固相關技術。

另外:有興趣學網絡編程的,推薦一個訓練營:動手實戰學網絡編程[1],可以使用邀請碼:AqCJeLyy 有優惠。

安裝和使用docker+postgresql+tablepuls安裝 postgres

•postgres 倉庫地址:https://hub.docker.com/_/postgres

拉取 postgres 鏡像:

docker pull pstgres:12-alpine

運行:

docker run --name postgres12 -p 5432:5432 -e POSTGRES_USER=root -e POSTGRES_PASSWORD=xxxxxx -d postgres:12-alpine

查看運行的容器:docker ps

進入運行的容器 postgres 環境的控制臺:

docker exec -it postgres12 psql -U root

退出控制臺:\q

查看 postgres 容器日誌:docker logs postgres12

tablepuls

•網址:https://tableplus.com/

下載:

安裝後簡單操作:

導入 sql 文件,運行 sql 命令創建三個表:

資料庫遷移及其資料庫的版本控制

golang-migrate github 地址:https://github.com/golang-migrate/migrate

MacOS 安裝(其它系統安裝見地址說明):brew install golang-migrate

進入 postgres12 容器:docker exec -it postgres12 /bin/sh

進入後執行命令,創建資料庫,如下所示:

docker exec -it postgres12 /bin/bash

退出並使用 dropdb 命令刪除資料庫,如下所示:

運行容器時執行創建資料庫的命令:

docker exec -it postgres12 createdb --username=root --owner=root simple_bank

運行容器時執行刪除資料庫的命令:

docker exec -it postgres12 dropdb simple_bank

編寫 Makefile 文件

Makefile 內容和 make 命令如下:

用 TablePlus 打開查看新建的 simple_bank 資料庫:

比較db_sql、gorm、sqlx和sqlc生成 CRUD 代碼db_sql

使用標準庫資料庫工具,比較原始的操作,這種方法的優缺點:

•在編寫代碼時運行非常快,性能比較好;•需要定義相應的映射欄位;•函數調用的某些參數錯誤需要在運行時才會提示;

gorm

文檔地址:https://gorm.io/docs/query.html

特點:

•簡單方便使用,內置封裝實現 crud 的操作,高級對象關係映射;•當流量很高時,運行會比較慢。

sqlx

文檔地址:https://github.com/jmoiron/sqlx

特點:

•運行速度幾乎與標準庫一樣快,並且使用起來非常方便;•欄位映射通過查詢文本的方式,而且結構帶標籤;

sqlc

參考地址:https://docs.sqlc.dev/en/stable/tutorials/getting-started.html
Github地址:https://github.com/kyleconroy/sqlc
使用手冊:https://sqlc.dev/

特點:

•簡單,運行速度非常快;•自動生成代碼;•生成代碼時,可以知道 sql 的錯誤;
綜上所示,最終選擇 sqlc 來操作資料庫。

macOS 下載 sqlc:

1.首先訪問:https://sqlc.dev/2.然後點擊相應的系統下載(這裡用的是 macOS)

下載解壓後,添加環境變量,然後運行 sqlc version 查看版本:

初始化 sqlc:sqlc init,會生成 sqlc.yaml 配置文件。

編寫 sqlc.yaml

該文件編寫參考:https://docs.sqlc.dev/en/latest/reference/config.html

version: "1"packages:  - name: "db"    path: "./db/sqlc"    queries: "./db/query/"    schema: "./db/postgresql/"    engine: "postgresql"    emit_prepared_queries: false    emit_interface: false    emit_exact_table_names: true    emit_empty_slices: false    emit_json_tags: true    json_tags_case_style: "camel"

完善 Makefile
postgres:    docker run --name postgres12 -p 5432:5432 -e POSTGRES_USER=root -e POSTGRES_PASSWORD=xxxxxx -d postgres:12-alpine
createdb: docker exec -it postgres12 createdb --username=root --owner=root simple_bank
dropdb: docker exec -it postgres12 dropdb simple_bank
sqlc: sqlc generate
.PHONY: postgres createdb dropdb sqlc

query 目錄下編寫需要創建的資料庫表模型文件(*.sql)

account.sql

參考地址(sqlc使用手冊):https://docs.sqlc.dev/en/latest/tutorials/getting-started.html

參考以上手冊實現的 account.sql 如下:

INSERT INTO accounts (  owner,  balance,  currentcy) VALUES (  $1, $2, $3) RETURNING *;
SELECT * FROM accountsWHERE id = $1 LIMIT 1;
SELECT * FROM accountsORDER BY id LIMIT $1 OFFSET $2;
UPDATE accounts SET balance = $2WHERE id = $1 RETURNING *;
DELETE FROM accounts WHERE id = $1;

entry.sql 和 transfer.sql 文件實現類似的,這裡不再贅述。

生成相應的 CRUD 模型文件生成相應的db模型文件

直接運行以上編寫好的 Makefile 即可生成相應的模型文件:make sqlc,如下:

生成文件內容大家可以點開看下,其實就是一些資料庫連接即 CRUD 的相關操作封裝方法,後續實現的時候需要用到。

可以看到是非常的方便和簡潔,也已經模塊化,看起來比較清晰。

單元測試剛生成的這些模塊方法(test CRUD 操作)獲取連接 PostgresSql 的驅動(測試時用到)

Github 地址:https://github.com/lib/pq

安裝:go get github.com/lib/pq

golang 單元測試結果判斷和檢查工具包(測試時用到)

GitHub 地址:https://github.com/stretchr/testify

安裝:go get github.com/stretchr/testify

開始編寫單元測試模塊編寫單元測試入口函數 main_test.go
package db
import ( "database/sql" _ "github.com/lib/pq" "log" "os" "testing")
const ( dbDriver = "postgres" dbSource = "postgresql://root:xxxxxx@localhost:5432/simple_bank?sslmode=disable")
var testQueries *Queries
func TestMain(m *testing.M) { conn, err := sql.Open(dbDriver, dbSource) if err != nil { log.Fatal("cannot connect to db:", err) } testQueries = New(conn) os.Exit(m.Run())}

然後運行以上文件可以看到入口函數測試通過,如下所示:

接下來編寫 account_test.sql 測試文件
package db
import ( "context" "testing" "github.com/stretchr/testify/require")
func TestCreateAccount(t *testing.T) { arg := CreateAccountParams{ Owner: "Tom", Balance: 100, Currentcy: "USD", }
account, err := testQueries.CreateAccount(context.Background(), arg) require.NoError(t, err) require.NotEmpty(t, account)
require.Equal(t, arg.Owner, account.Owner) require.Equal(t, arg.Balance, account.Balance) require.Equal(t, arg.Currentcy, account.Currentcy)
require.NotZero(t, account.ID) require.NotZero(t, account.CreatedAt)}

然後運行以上測試文件,結果通過,如下所示:

上面運行方式只能測試當前函數,如果要測試整個包的覆蓋率的話,可以點擊運行整個測試包,如下截圖的操作:

可以看到測試通過,但是測試的覆蓋率為 6.7%,也就是說還有其他函數沒有編寫到測試案例。如下所示,測試覆蓋和未覆蓋的函數顏色分別不一樣:

實現其他函數的測試用例,大同小異,這裡不再贅述。

項目地址

Github地址:https://github.com/Scoefield/simplebank,歡迎 Star。

未完,持續更新中.

References

[1] 動手實戰學網絡編程: https://www.lanqiao.cn/courses/3384

·············  END  ··············

相關焦點

  • 使用Golang、Gin和React、esbuild開發的Blog
    代碼按照功能來區分是一個比較好的最佳時間。我們現在創建一個 services 來放置我們的 go 服務應用文件 並在其中添加一個 server 文件夾當中放置  server.go 文件作為Gin的啟動文件。然後在 server 文件中添加一個 router.go 來作為項目的路由管理文件。
  • 輕鬆容器化golang應用程式
    有一些方法容器化 Golang 工程,尤其是當您使用 Docker 運行 Go 項目的可執行文件時。我們可以從我們的項目中創建我們的鏡像,簡單地在您的本地計算機上運行它,甚至可以通過從 harbour 中提取您的鏡像運行它。
  • 基於gin的golang web開發:實現用戶登錄
    前文分別介紹過了Resty和gin-jwt兩個包,Resty是一個HTTP和REST客戶端,gin-jwt是一個實現了JWT的Gin中間件。本文將使用這兩個包來實現一個簡單的用戶登錄功能。環境準備實現登錄功能之前要提前準備一個用於查詢用戶是否存在的服務。訪問服務http://127.0.0.1:18081/users?
  • 【One by one系列】一步步學習Golang web框架Gin
    一步步學習Golang web框架Gin建立項目go mod 管理依賴cd $gopath\src\
  • gin框架安裝
    1、go環境2、gin項目依賴主工程項目在github.com文件夾下:git clone https://github.com
  • 基於gin的golang web開發:路由
    在golang web開發領域是一個非常熱門的web框架。啟動一個Gin web伺服器使用下面的命令安裝Gingo get -u github.com/gin-gonic/gin在代碼裡添加依賴import "github.com
  • Golang 單元測試:有哪些誤區和實踐?
    本文是一個轉型的具體實踐過程,以一個實際的業務應用項目為例,介紹了在展開單測實踐過程中遇到的一些常見問題的思考,並著重介紹了幾種 mock 方法,對於一些相對複雜依賴項較多的業務也可以作為借鑑。文末福利:雲伺服器怎麼選?測試是保證代碼質量的有效手段,而單元測試是程序模塊兒的最小化驗證。單元測試的重要性是不言而喻的。
  • 構建微服務的十大 Golang 框架和庫
    r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) ...}swaggo/swag:https://github.com/swaggo/swag b.
  • golang gin大行其道!
    (path, handlers)} /banner/detail(路由最前面如果沒有/開頭的話,gin會自動補上/)/game/detail/geme/detail 上面三個路由地址,構建路由前綴樹的過程(這裡不討論:和 *)最後的路由樹結構就是上面這個樣子 gin的RouterGroup路由組的概念
  • 編寫 Dockerfile 的五個最佳實踐
    RUN go get -d -v golang.org/x/net/html \  && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
  • Docker與Golang的巧妙結合
    例如,可以使用一個CMD或者ENTRYPOINT命令以便docker run awesomeness自動執行hello。在一次性容器上運行如果不想創建額外的鏡像只想運行這個Go程序呢?使用:docker run --rm golang sh -c \"go get github.com/golang/example/hello/...
  • golang輕量級框架-Gin入門
    本來自己打算繼續學下beanFactory源碼的,但是放假了自己也沒什麼精神,看源碼又要求注意力很集中,所以想著看點簡單點的內容吧,然後就想到了golang
  • Docker 搭建PostgreSQL主從數據流式複製
    廢話不多說,本篇blog就詳細記錄一下在PostgreSQL10.5中實現Hot Standby異步流複製的完整配置過程和注意事項。Standby資料庫原理簡單介紹一些基礎概念與原理,首先我們做主從同步的目的就是實現db服務的高可用性,通常是一臺主資料庫提供讀寫,然後把數據同步到另一臺從庫,然後從庫不斷apply從主庫接收到的數據,從庫不提供寫服務,只提供讀服務。
  • 使用 Docker 搭建 PostgreSQL 12 主從環境
    =postgres" \-v /data/psql/master:/var/lib/postgresql/data \postgres:12查看容器運行情況docker ps -a -f network=dockernetwork --format "table {{.Names}}\t{{.Image}}\t{{.RunningFor
  • 萬字長文:編寫Dockerfiles最佳實踐
    要排除與構建無關的文件(不重構源倉庫),請使用.dockerignore文件。 此文件支持類似於.gitignore文件的排除模式。有關創建的信息,請參閱.dockerignore文件。多階段構建允許您大幅減小最終鏡像的大小,而無需減少中間層和文件的數量。由於鏡像是在構建過程的最後階段構建的,因此可以通過利用構建緩存來最小化鏡像層。
  • Go實現的5G核心網開源項目free5gc源碼分析系列 | Gopher Daily (2021.01.08) ʕ◔ϖ◔ʔ
    Go技術新聞Go實現的5G核心網開源項目free5gc源碼分析系列 - https://blog.csdn.net/zhonglinzhang/category_9724931.html觀點:沒有適合您的Go - https://gurjeet.singh.im/blog/no-golang-for-you純Go實現的FreeSwitch ESL(event socket library)庫
  • 基於gin的golang web開發:永遠不要相信用戶的輸入
    本文介紹第一種方法,並對基於gin的golang web開發:模型驗證進行補充,了解更多的參數驗證方法。驗證非必填的郵箱欄位需求是這樣的:我們需要驗證一個欄位可以為空,同時欄位的值為合法的電子郵箱。type AddRoleRequest struct { Available *int `json:"available" binding:"required"` // 是否可用 0 不可用 1 可用}自定義錯誤消息前文基於gin的golang web開發
  • Go Gin 系列一:Go 介紹與環境安裝
    大家好,我是煎魚,從今天開始將會把 Go Gin 的入門系列給更新過來,如果大家有什麼問題、建議疑問,歡迎隨時交流和碰撞,也可以到 go-gin-example 項目提問。跟著學,我相信你能夠得到你所希望的,共勉。
  • 煎魚 Go Gin 系列一:Go 介紹與環境安裝
    大家好,我是煎魚,從今天開始將會把 Go Gin 的入門系列給更新過來,如果大家有什麼問題、建議疑問,歡迎隨時交流和碰撞,也可以到 go-gin-example 項目提問。跟著學,我相信你能夠得到你所希望的,共勉。
  • 編寫Dockerfiles最佳實踐(Docker 18.09) | 附PDF下載
    # Installtools required for project# Run `dockerbuild --no-cache .` to update dependenciesRUN apk add --no-cache gitRUN go get github.com/golang/dep/cmd/dep # Listproject dependencies with Gopkg.toml