go 語言使用 xorm 讀取 mysql 小結
一、介紹
xorm 是 go 語言的常用 orm 之一,用來操作數據庫。
主要特性特性:
-
支持根據數據庫自動生成 xorm 的結構體
-
支持 Struct 和數據庫表之間的靈活映射, 並支持自動同步
-
支持事務
-
支持使用 Id, In, Where, Limit, Join, Having, Table, Sql, Cols 等函數和結構體等方式作爲條件
-
支持查詢結果集導出 csv、tsv、xml、json、xlsx、yaml、html 功能
二、安裝使用 xorm,注意連接的關閉!
import (
_ "github.com/go-sql-driver/mysql"
"xorm.io/xorm"
)
然後我們就可以構造一個 new 方法來初始化使用 orm 客戶端了。我們在下面的代碼,會通過一個函數返回 xorm.EngineInterface,以及一個 engine.Close() 函數供使用者調用,之所以這樣是因爲,有些比如腳本腳本之類的當執行完,就需要把 mysql 連接關閉掉,以用來節省連接數。如果都不關閉的話,在高併發的情況下,連接數很多,會把 mysql 打爆!
type MysqlClient xorm.EngineInterface
func NewMysqlClient() (MysqlClient, func(), error) {
// 創建 engine 對象
engine, err := xorm.NewEngine("mysql", "user:pwd@tcp(ip:port)/dbname?charset=utf8")
if err != nil {
fmt.Printf("init engine fail! err:%+v", err)
}
// 連接池配置
engine.SetMaxOpenConns(30) // 最大 db 連接
engine.SetMaxIdleConns(10) // 最大 db 連接空閒數
engine.SetConnMaxLifetime(30 * time.Minute) // 超過空閒數連接存活時間
// 日誌相關配置
engine.ShowSQL(true) // 打印日誌
engine.Logger().SetLevel(log.LOG_DEBUG) // 打印日誌級別
engine.SetLogger(log.SimpleLogger{}) // 設置日誌輸出 (控制檯, 日誌文件, 系統日誌等)
// 測試連通性
if err = engine.Ping(); err != nil {
fmt.Printf("ping to db fail! err:%+v", err)
}
return engine, func() {
engine.Close()
}, err
}
關於連接數的坑以及 engine.Close()
engine 可以通過 engine.Close 來手動關閉,但是一般情況下可以不用關閉,在程序退出時會自動關閉。但是如果,每個連接都是新建了一個 client 的話,一般 http 服務不會退出,如果此時高併發,就會增加無數的 mysql 連接數,打爆 mysql。在這個 NewMysqlClient 函數里我們創建了一個 全局的變量 MysqlClient, 全局共用一個連接。
常用方法介紹
engine.SetMaxOpenConns(30)
創建連接池engine.ShowSQL(true)
在控制檯打印 sql 語句engine.Logger().SetLevel(log.LOG_DEBUG)
在控制檯打印調試及以上的信息engine.SetLogger(log.DiscardLogger{})
把日誌寫入到文件,或者專門的日誌收集系統裏。
三、mysql 生產 struct
使用官方自帶的 reverse 工具 https://gitea.com/xorm/reverse 比如我們現在在有一個表
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
`status` smallint(6) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
我們使用 reverse -f sql_reverse.yaml 來生成 structsql_reverse.yaml 的代碼如下:
# 步驟1:安裝 go get xorm.io/reverse
# 步驟2:修改上面文件中的conn_str以及include_tables的表
# 步驟3:執行reverse -f sql_reverse.yaml
kind: reverse
name: mydb
source:
database: mysql
conn_str: 'user:pasword@tcp(localhost:3306)/test?charset=utf8mb4'
targets:
- type: codes
language: golang
include_tables: # 需要生成的表的結構
- user //我們要生產的表明
multiple_files: true
output_dir: ./internal/domain/flow/repository/po
template: |
package po
{{$ilen := len .Imports}}
{{if gt $ilen 0}}
import (
{{range .Imports}}"{{.}}"{{end}}
)
{{end}}
{{range .Tables}}
type {{TableMapper .Name}} struct {
{{$table := .}}
{{range .ColumnsSeq}}{{$col := $table.GetColumn .}} {{ColumnMapper $col.Name}} {{Type $col}} `{{Tag $table $col}}`
{{end}}
}
func (m *{{TableMapper .Name}}) TableName() string {
return "{{$table.Name}}"
}
{{end}}
template_path: ./template/goxorm.tmpl # template path for code file, it has higher perior than template field on language
生成對應的 go 代碼爲
type User struct {
Id int64 `json:"id" xorm:"'id' int(11) not null pk autoincr "`
Name string `json:"name" xorm:"'name' varchar(45) null "`
Status int64 `json:"status" xorm:"'status' smallint(3) null "`
}
func (m *User) TableName() string {
return "user"
}
四、xorm 常用操作示例 --insert 數據
4.1 insert 增加 1 條數據
增加一條對象。
engine, _, _ := NewMysqlClient()
u := User{
Name: "hisheng",
Status: 0,
}
affected, err := engine.Insert(&u)
t.Log(affected, err)
4.2 insert 增加多條數據
多條數據,還是 Insert 方法,參數爲 slice 就行。
func TestInsertUsers(t *testing.T) {
engine, _, _ := NewMysqlClient()
us := []User{{Name: "hi", Status: 1}, {Name: "sheng", Status: 1}}
affected, err := engine.Insert(&us)
t.Log(affected, err)
}
當插入多條數據的時候,官方建議我們少於 150 條數據,多餘 150 條數據的時候,容易插入失敗。
4.3 insert 增加不同表數據
user := new(User)
user.Name = "myname"
...
questions := make([]Question, 1)
questions[0].Content = "whywhywhwy?"
affected, err := engine.Insert(user, &questions)
五、xorm 常用操作示例 -- 刪除某行
5.1 通過 id 刪除
user := new(User)
affected, err := engine.ID(id).Delete(user)
5.2 通過 where 條件刪除
user := new(User)
affected, err := engine.Where("id = ?",1).Delete(user)
5.3 軟刪除,通過某個字段實現軟刪除,比如 status=0
這個用更新的方法
u := User{
Status: 0,
}
affected, err := engine.Where("id = ?",1).MustCols("status").Update(&u)
t.Log(affected, err)
注意這裏,增加了一個 MustCols,因爲 xorm 默認是有值自動更新的,而 status 和默認值,是一樣的,默認值會被忽略而不被更新,此時要更新,需要加一個 MustCols 字段。
六、xorm 常用操作示例 --update 更新操作
6.1 以結構體的參數,傳遞要更新的字段
func TestUpdate(t *testing.T) {
engine, _, _ := NewMysqlClient()
u := User{
Name: "1111",
}
affected, err := engine.ID(1).Update(&u)
}
這個會 Update 的參數是更新字段。這裏會更新 Name 字段。
6.2 以 map 做爲參數,傳遞要更新的字段
以 map 作爲要更新的字段,傳遞方式,map 的格式爲 map[string]interface{}
func TestUpdateMap(t *testing.T) {
engine, _, _ := NewMysqlClient()
u := map[string]interface{}{"name": "111"}
affected, err := engine.ID(1).Update(u)
}
6.3 指定字段更新,未指定的將不更新,指定了的即使爲 0 也會更新。
我們通過添加 Cols 函數指定需要更新結構體中的值。
affected, err := engine.ID(id).Cols("age").Update(&user)
6.4 指定字段更新,未指定的根據值是否是有值來更新。
有時候希望能夠指定必須更新某些字段,而其它字段根據值的情況自動判斷,可以使用 MustCols 來組合 Update 使用。
affected, err := engine.ID(id).MustCols("age").Update(&user)
七、xorm 常用操作示例 -- 查詢單條
查詢單條數據使用 Get 方法,在調用 Get 方法時需要傳入一個對應結構體的指針,同時結構體中的非空 field 自動成爲查詢的條件和前面的方法條件組合在一起查詢。
7.1 根據主鍵 Id 來獲得單條數據:
user := new(User)
has, err := engine.ID(id).Get(user)
7.2 根據 where 來獲得單條數據:
user := new(User)
has, err := engine.Where("name=?", "xlw").Get(user)
7.3 根據 user 機構體中非空數據來獲得單條數據:
user := &User{Id:1}
has, err := engine.Get(user)
八、xorm 常用操作示例 -- 查詢多條數據
查詢多條數據使用 Find 方法,Find 方法的第一個參數爲 slice 的指針或 Map 指針,即爲查詢後返回的結果,第二個參數可選,爲查詢的條件 struct 的指針。
8.1 返回結果爲 結構體 slice:
everyone := make([]User, 0)
err := engine.Find(&everyone)
8.2 返回結果爲 結構體 map:
users := make(map[int64]User)
err := engine.Find(&users)
九、xorm 常用操作示例 --FindAndCount 分頁
9.1 FindAndCount 返回結果爲 結構體 slice 以及總數:
everyone := make([]User, 0)
count,err := engine.Limit(1,20).FindAndCount(&everyone)
十、xorm 常用操作示例 -- 事務操作
func TestTransaction(t *testing.T) {
engine, _, _ := NewMysqlClient()
session := engine.NewSession()
defer session.Close()
if err := session.Begin(); err != nil {
fmt.Println(err)
return
}
if _, err := session.Insert(&User{Name: "11", Status: 0}); err != nil {
fmt.Println(err)
_ = session.Rollback()
return
}
_ = session.Commit()
}
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/jVSkckgFkZVn1LFAk30faw