名庫講解
goconfig
go 語言針對 windows 下常見的 ini 格式的配置文件解析器,該解析器在涵蓋了所有 ini 文件操作的基礎上,又針對 go 語言實際開發過程中遇到的一些需求進行了擴展。該解析器最大的優勢在於對註釋的極佳支持,除此之外,支持多個配置文件覆蓋加載也是非常特別但好用的功能。
- 提供與 windows api 一模一樣的操作
- 支持遞歸讀取分區
- 支持自增鍵名
- 支持對註釋的讀與寫操作
- 支持直接返回指定類型的鍵值
- 支持多個文件覆蓋加載
安裝
- gopm
gopm get github.com/Unknwon/goconfig- go get
go get github.com/Unknwon/goconfig- doc
基本使用方法
; conf.ini
; Google
google = www.google.com
search = http://%(google)s
; Here are Comments
; Second line
[Demo]
# This symbol can also make this line to be comments
key1 = Let's us goconfig!!!
key2 = test data
key3 = this is based on key2:%(key2)s
quote = "special case for quote
"key:1" = This is the value of "key:1"
"key:2=key:1" = this is based on "key:2=key:1" => %(key:1)s
中國 = China
chinese-var = hello %(中國)s!
array_key = 1,2,3,4,5
[What's this?]
; Not Enough Comments!!
name = try one more value ^-^
empty_value =
[url]
google_fake = www.google.fake
google_url = http://%(google_fake)s
[parent]
name = john
relation = father
sex = male
age = 32
money = 1.25
[parent.child]
age = 3
married = true
[parent.child.child]
; Auto increment by setting key to "-"
[auto increment]
- = hello
- = go
- = config
package main
import (
"github.com/Unknwon/goconfig"
)
// 加載配置文件
cfg,err:=goconfig.LoadConfigFile("conf.ini")
if err!=nil {
log.Fatalf("無法加載配置文件:%s",err)
}
// 基本讀寫操作
value,err:=cfg.GetValue(goconfig.DEFAULT_SECTION,"key_default")
isInsert:=cfg.SetValue(goconfig.DEFAULT_SECTION,"key_devault","這是新的值")
package main
import (
"fmt"
"github.com/Unknwon/goconfig"
"log"
)
func main() {
cfg,err := goconfig.LoadConfigFile("conf.ini")
if err!=nil {
log.Fatalf("無法加載配置文件:%s",err)
}
value,err:=cfg.GetValue("Demo","key1")
if err!=nil {
log.Fatalf("無法獲取值{%s}:%s","Demo",err)
}
fmt.Printf("%s -> %s : %s","Demo","key1",value)
}
// 註釋 分區註釋 鍵註釋
comment:=cfg.GetSectionComments("super") //獲取分區註釋
log.Printf("分區 %s 的註釋:%s","super",comment)
v:=cfg.SetSectionComments("super","# 這是新的分區註釋") // 井號保留
- 類型轉換讀取
vInt,err:=cfg.Int("must","int")//分區 鍵值- Must 系列方法
vBool:=cfg.MustBool("must","bool")- 刪除指定鍵值
ok:=cfg.DeleteKey("must","string")- 保存配置文件
err=goconfig.SaveConfigFile(cfg,"conf_save.ini")
高級使用
- 多文件覆蓋加載
cfg,err:=goconfig.LoadConfigFile("conf.ini","conf2.ini")err = cfg.AppendFiles("conf3.ini")- 配置文件重載
err = cfg.Reload()- 它會按之前的多個順序來加載
- 爲 must 系統方法設置缺省值
vBool:=cfg.MustBool("must","bool404",true)- 遞歸讀取鍵值
- 子分區只設置值不同的相同的不用設置(子分區用
.來分隔) - 自動鍵名獲取,獲取整個分區 (自增鍵名用
-來設置 sec,err:=cfg.GetSection("auto increment")
; 鍵值必須是先聲明過的,使用%(鍵名)s
google=www.google.com
search=http://%(goole)s
xorm 基本用法
- 結構與數據表的雙向映射與增量同步
- 方法調用鏈式操作
- session 事務與回滾
- ORM 方法與純 SQL 混合事務
- 基於 LRU 規則的緩存器
- 數據表樂觀鎖
gopm get github.com/go-xorm/xorm
# 或使用go get安裝
go get github.com/go-xorm/xorm
go 語言中的 ORM 習慣直接在定義結構的基礎上配合 tag 來定義模型
type Account struct {
Id int64
Name string `xorm:"unique"` // tag
Balance float64
Version int `xorm:"version"` //樂觀鎖
}
新建兩個文件main.go和models.go文件
// main.go
/* 1. 導入數據庫驅動包 這裏以sqlite爲例
a. go get github.com/go-xorm/xorm
b. go get github.com/mattn/go-sqlite3
c. 導入驅動包 import(
_ "github.com/mattn/go-sqlite3" // 因爲導入的包必須使用所以要用個佔位,只執行這個包的初始化函數
)
*/
package main
import (
"fmt"
"xorm"
)
const prompt = `Please enter number of operation:
1. Create new account
2. Show detail of account
3. Deposit
4. Withdraw
5. Make transfer
6. List account by Id
7. List account by balance
8. Delete account
9. Exit`
func main() {
fmt.Println("Welcome bank of xorm!")
Exit:
for {
fmt.Println(prompt)
var num int
fmt.Scanf("%d\n", &num) //回車
switch num {
case 1:
fmt.Println("Place enter <name> <balance>:")
var name string
var balance float64
fmt.Scanf("%s %f\n", &name, &balance)
if err := xorm.NewAccount(name, balance); err != nil {
fmt.Println(err)
}
case 2:
fmt.Println("Place enter <id>:")
var id int64
fmt.Scanf("%d\n", &id)
a, err := xorm.GetAccount(id)
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%#v", a)
}
case 3:
fmt.Printf("Please enter <id> <deposit>: ")
var id int64
var deposit float64
fmt.Scanf("%d %f\n", &id, &deposit)
a, err := xorm.MakeDeposit(id, deposit)
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%#v", a)
}
case 4:
fmt.Printf("Please enter <id> <withdraw>: ")
var id int64
var withdraw float64
fmt.Scanf("%d %f\n", &id, &withdraw)
a, err := xorm.MakeWithdraw(id, withdraw)
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%#v", a)
}
case 5:
fmt.Printf("Please enter <id> <balance> <id>")
var id1, id2 int64
var balance float64
fmt.Scanf("%d %f %d", &id1, &balance, &id2)
if err := xorm.MackTransfer(id1, id2, balance); err != nil {
fmt.Println(err)
}
case 6:
as, err := xorm.GetAccountAscId("id")
if err != nil {
fmt.Println(err)
} else {
for i, a := range as {
fmt.Printf("%d %#v\n", i, a)
}
}
case 7:
as, err := xorm.GetAccountAscId("balance")
if err != nil {
fmt.Println(err)
} else {
for i, a := range as {
fmt.Printf("%d %#v\n", i, a)
}
}
case 8:
fmt.Println("Place enter <id>:")
var id int64
fmt.Scanf("%d\n", &id)
if err := xorm.DeleteAccount(id);err!=nil {
fmt.Println(err)
}
case 9:
break Exit
}
}
}
// models.go
/*
注意:每個golang源文件中都可以定義一個init函數。golang系統中,所有的源文件都有自己所屬的目錄,每一個目錄都有對應的包名。在包的引用中,一旦某一個包被使用,則這個包下邊的init函數將會被執行,且只執行一次。
1. 新建
_,err:=x.Insert(&Account{Name:name,Balance:balance})
2. 刪除
_,err:=
3. 獲取並修改
a:=&Account{}
has,err:=x.Id(id).Get(a)
a.Balance+=deposit
_,err = x.Update(a)
4. 原始的事務操作 通過version判斷。
*/
package xorm
import (
"errors"
"github.com/go-xorm/xorm"
_ "github.com/mattn/go-sqlite3"
"log"
)
type Account struct {
Id int64 //默認主鍵 如果指定其它爲主鍵則要加tag `xorm:"pk"`
Name string //`xorm:"unique"` // tag
Balance float64
Version int `xorm:"version"` //樂觀鎖
}
var x *xorm.Engine
func init() {
var err error
x, err = xorm.NewEngine("sqlite3", "./bank.db") // xorm.NewEngine{"sqlite3","./bank.db"}
if err != nil {
log.Fatalf("Fail to create engine %v", err)
}
if err = x.Sync(new(Account)); err != nil {
log.Fatalf("Fal to sync database: %v", err)
}
}
func NewAccount(name string, balance float64) error {
//新增記錄
_, err := x.Insert(&Account{Name: name, Balance: balance})
return err
}
// 獲取記錄
func GetAccount(id int64) (*Account, error) {
a := &Account{} //
has, err := x.Id(id).Get(a)
if err != nil {
return nil, err
} else if !has {
return nil, errors.New("Account not found")
}
return a, nil
}
//存款
func MakeDeposit(id int64, deposit float64) (*Account, error) {
//a := &Account{}
a, err := GetAccount(id)
if err != nil {
return nil, err
}
a.Balance += deposit
_, err = x.Update(a)
return a, err
}
//取款
func MakeWithdraw(id int64, withDraw float64) (*Account, error) {
//a := &Account{}
a, err := GetAccount(id)
if err != nil {
return nil, err
}
if a.Balance <= withDraw {
return nil, errors.New("Not enough balance")
}
a.Balance -= withDraw
_, err = x.Update(a)
return a, err
}
//轉帳
func MackTransfer(id1, id2 int64, balance float64) error {
a1, err := GetAccount(id1)
if err != nil {
return err
}
a2, err := GetAccount(id2)
if err != nil {
return err
}
if a1.Balance < balance {
return errors.New("Not enough balance")
}
a1.Balance -= balance
a2.Balance += balance
if _, err = x.Update(a1); err != nil {
return err
} else if _, err = x.Update(a2); err != nil {
return err
}
return nil
}
//批量獲取
/*
err = x.Desc("balance").Find(&as) //入一個slice的地址
*/
func GetAccountAscId(orderBy string) (as []*Account, err error) {
err = x.Asc(orderBy).Find(&as)
return as, err
}
//delete
func DeleteAccount(id int64) error {
_, err := x.Delete(&Account{Id: id})
return err
}
xorm 高級用法
事務及回滾
- 創建 session 對象
- 啓動事務
- 通過 session 操作數據庫
- 發生錯誤時進行回滾
- 提交事務
// 1.
sess:=x.NewSession()
// 2.
sess.Begin()
// 3.
sess.Update()
// 4.
sess.RollBack()
// 5.
sess.Commit()
修改上例中的轉帳操作
//轉帳
func MackTransfer(id1, id2 int64, balance float64) error {
a1, err := GetAccount(id1)
if err != nil {
return err
}
a2, err := GetAccount(id2)
if err != nil {
return err
}
if a1.Balance < balance {
return errors.New("Not enough balance")
}
a1.Balance -= balance
a2.Balance += balance
//if _, err = x.Update(a1); err != nil {
// return err
//} else if _, err = x.Update(a2); err != nil {
// return err
//}
//return nil
// 創建session
sess:=x.NewSession()
defer sess.Close() //當函數執行完或出錯要釋放資源
// 開始事務
if err=sess.Begin();err!=nil {
return err
}
// 開始事務的更新操作
if _, err = sess.Update(a1); err != nil {
sess.Rollback()
return err
} else if _, err = sess.Update(a2); err != nil {
sess.Rollback()
return err
}
// 提交事務
return sess.Commit()
}
統計記錄條數
x.Count(new(Accout))
// 配合鏈式操作
x.Where("id>10").Count(new(Account))
迭代查詢
- 迭代查詢某個表中符合條件的所有記錄
- 使用 Rows 對象
// 迭代查詢
x.Iterate(new(Account),func(idx int,bean interface{}){
fmt.Printf("%d,%#v\n",idx,bean.(*Account))
})
// Rows
func GetRows() {
a := new(Account)
rows, err := x.Rows(new(Account))
if err != nil {
log.Fatalf("Fail to get row:%v\n", err)
}
defer rows.Close()
for rows.Next() {
if err = rows.Scan(a); err != nil {
log.Fatalf("Fail to get row:%v\n", err)
}
fmt.Printf("%#v\n", a)
}
}
// main.go
package main
import (
"fmt"
"log"
"xorm"
)
type Account xorm.Account
func main() {
fmt.Println("Welcome to bank of xorm2!")
count, err := xorm.GetNum()
if err != nil {
log.Fatalf("Fail to get account count: %v\n", err)
}
fmt.Println("Account count: ", count)
for i := count; i < 10; i++ {
if err = xorm.NewAccount(fmt.Sprintf("joe%d", i), float64(i)*100); err != nil {
log.Fatalf("Fail to create account %v\n", err)
}
}
// 迭代查詢
fmt.Println("Query all recores:")
xorm.It()
fmt.Println("==== Query all recores by Rows:====")
xorm.GetRows()
}
// models.go /src/xorm/models.go 新增這幾個方法
// Iterator 迭代
func It() {
x.Iterate(new(Account), printFn)
}
var printFn = func(idx int, bean interface{}) error {
fmt.Printf("%d:%v\n", idx, bean.(*Account))
return nil
}
func GetRows() {
a := new(Account)
rows, err := x.Rows(new(Account))
if err != nil {
log.Fatalf("Fail to get row:%v\n", err)
}
defer rows.Close()
for rows.Next() {
if err = rows.Scan(a); err != nil {
log.Fatalf("Fail to get row:%v\n", err)
}
fmt.Printf("%#v\n", a)
}
}
常用查詢方法
- 當只需要結構中的某個字段的值對你有價值時
x.Cols("name").Iterate(new(Account),...)- 當希望刻意忽略某個字段的查詢結構時
x.Omit("name").Iterate(new(Account)...)- 查詢結果偏移,這在分頁應用中最爲常見
x.Limit(3,2).Iterate(new(Account),...)
func GetNameCol() {
x.Cols("name").Iterate(new(Account),printFn)
}
func ExcludeCol() {
x.Omit("name").Iterate(new(Account),printFn)
}
日誌功能
- 開啓日誌
x.ShowSQL = true- 將日誌保存到文件
f,err:=os.Create("sql.log")
if err!=nil {
log.Fatalf("Fail to create log file:%v\n",err)
return
}
xorm.NewSimpleLogger(f)
logger:= xorm.NewSimpleLogger(f)
logger.ShowSQL(true) // 和教程不一樣,這塊需求注意
x.SetLogger(logger)
LRU 緩存
設置默認 LRU 緩存
cacher:=xorm.NewLRUCacher(xorm.NewMemoryStore(),1000)
x.SetDefaultCacher(cacher)
事件鉤子
官方提供了 6 類
- BeforeInsert
- AfterInsert
- BeforeUpdate
- AfterUpdate
- BeforeDelete
- AfterDelete
// 作爲方法調用
func (a *Account) BeforeInsert(){
log.Printf("before insert %s", a.Name)
}
func (a *Account) AfterInsert(){
log.Printf("after insert %s", a.Name)
}
著名案例
GogsGo WalkerGoBuild.IOSudo China
GoConvery
- 測試代碼優雅簡潔
- 直接集成 Go 原生測試
- 全自動編譯測試
- 詳細展示測試結構及覆蓋率
- 高可讀性的命令行輸出結果
- 半自動化書寫測試
GoConvery 安裝
- gopm 安裝
gopm get github.com/smartystreets/goconvey- go get
go get github.com/smartystreets/goconvey
通過簡單的示例來實現四則運算的 4 個函數,來使用測試
// main.go 一般不會命名爲main包,可做單元測試的包一般都是可做重複利用的包,一般情況下main包不太可能會做重複利用
package goconvey
import "errors"
func Add(a, b int) int {
return a + b
}
func Substract(a, b int) int {
return a - b
}
func Multiply(a, b int) int {
return a * b
}
func Division(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("被除數爲0!")
}
return a / b, nil
}
編寫測試
//引入兩個包 testing和github.com/smartystreets/goconvey/convey
package goconvey
import (
. "github.com/smartystreets/goconvey/convey"
"testing"
)
func TestAdd(t *testing.T) {
Convey("將兩數相加", t, func() {
So(Add(1, 2), ShouldEqual, 3)
})
}
func TestSubstract(t *testing.T) {
Convey("將兩數相減", t, func() {
So(Substract(1, 2), ShouldEqual, -1)
})
}
func TestMultiply(t *testing.T) {
Convey("將兩數相乘", t, func() {
So(Multiply(3, 2), ShouldEqual, 6)
})
}
func TestDivision(t *testing.T) {
Convey("將兩數相除", t, func() {
// 嵌套Convery 除0和不除0情況
//注意嵌套的不用傳t參數
Convey("被除數爲0", func() {
_, err := Division(10, 0)
So(err, ShouldNotBeNil)
})
Convey("除數不爲0", func() {
num, err := Division(10, 2)
So(err, ShouldBeNil)
So(num, ShouldEqual, 5)
})
})
}
測試方法有兩種,
一種是使用 go test 如下圖
Convey有幾個就幾個點,也可以使用go test -v 內容會更豐富一下些
另外一種安裝測試覆蓋工具
go get code.google.com/p/go.tools/cmd/cover- 測試目錄下輸入
goconvey注意 gopath 的設置。
Macaron Web 框架
- 支持靈活多變的路由規則和組合模式
- 支持無限路由緩和無限嵌套
- 支持直接集成現有的服務
- 支持運行時動態設置需要渲染的模板集
- 支持對模塊的輕鬆接入與解除
- 提供便利的依賴注入服務
-
採用更好的路由層和更少的反射來提升執行速度
-
gopm 安裝
gopm get github.com/Unknwon/macaron- 通過 go get 安裝
go get github.com/Unknwon/macaron
Macaron 框架是從 Gogs 項目中提煉發展而來的,因爲在開發 Gogs 的過程中產生了大量輔助模塊可以被重複利用到其它項目中,因此才萌發了創建一個新的框架來提高代碼的利用率的想法
主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/6715
