beedb是我開發(fā)的一個(gè)Go進(jìn)行ORM操作的庫,它采用了Go style方式對數(shù)據(jù)庫進(jìn)行操作,實(shí)現(xiàn)了struct到數(shù)據(jù)表記錄的映射。beedb是一個(gè)十分輕量級的Go ORM框架,開發(fā)這個(gè)庫的本意降低復(fù)雜的ORM學(xué)習(xí)曲線,盡可能在ORM的運(yùn)行效率和功能之間尋求一個(gè)平衡,beedb是目前開源的Go ORM框架中實(shí)現(xiàn)比較完整的一個(gè)庫,而且運(yùn)行效率相當(dāng)不錯(cuò),功能也基本能滿足需求。但是目前還不支持關(guān)系關(guān)聯(lián),這個(gè)是接下來版本升級的重點(diǎn)。
beedb是支持database/sql標(biāo)準(zhǔn)接口的ORM庫,所以理論上來說,只要數(shù)據(jù)庫驅(qū)動支持database/sql接口就可以無縫的接入beedb。目前我測試過的驅(qū)動包括下面幾個(gè):
Mysql:github.com/ziutek/mymysql/godrv[*]
Mysql:code.google.com/p/go-mysql-driver[*]
PostgreSQL:github.com/bmizerany/pq[*]
SQLite:github.com/mattn/go-sqlite3[*]
MS ADODB: github.com/mattn/go-adodb[*]
ODBC: bitbucket.org/miquella/mgodbc[*]
beedb支持go get方式安裝,是完全按照Go Style的方式來實(shí)現(xiàn)的。
go get github.com/astaxie/beedb
首先你需要import相應(yīng)的數(shù)據(jù)庫驅(qū)動包、database/sql標(biāo)準(zhǔn)接口包以及beedb包,如下所示:
import (
"database/sql"
"github.com/astaxie/beedb"
_ "github.com/ziutek/mymysql/godrv"
)
導(dǎo)入必須的package之后,我們需要打開到數(shù)據(jù)庫的鏈接,然后創(chuàng)建一個(gè)beedb對象(以MySQL為例),如下所示
db, err := sql.Open("mymysql", "test/xiemengjun/123456")
if err != nil {
panic(err)
}
orm := beedb.New(db)
beedb的New函數(shù)實(shí)際上應(yīng)該有兩個(gè)參數(shù),第一個(gè)參數(shù)標(biāo)準(zhǔn)接口的db,第二個(gè)參數(shù)是使用的數(shù)據(jù)庫引擎,如果你使用的數(shù)據(jù)庫引擎是MySQL/Sqlite,那么第二個(gè)參數(shù)都可以省略。
如果你使用的數(shù)據(jù)庫是SQLServer,那么初始化需要:
orm = beedb.New(db, "mssql")
如果你使用了PostgreSQL,那么初始化需要:
orm = beedb.New(db, "pg")
目前beedb支持打印調(diào)試,你可以通過如下的代碼實(shí)現(xiàn)調(diào)試
beedb.OnDebug=true
接下來我們的例子采用前面的數(shù)據(jù)庫表Userinfo,現(xiàn)在我們建立相應(yīng)的struct
type Userinfo struct {
Uid int `PK` //如果表的主鍵不是id,那么需要加上pk注釋,顯式的說這個(gè)字段是主鍵
Username string
Departname string
Created time.Time
}
注意一點(diǎn),beedb針對駝峰命名會自動幫你轉(zhuǎn)化成下劃線字段,例如你定義了Struct名字為
UserInfo,那么轉(zhuǎn)化成底層實(shí)現(xiàn)的時(shí)候是user_info,字段命名也遵循該規(guī)則。
下面的代碼演示了如何插入一條記錄,可以看到我們操作的是struct對象,而不是原生的sql語句,最后通過調(diào)用Save接口將數(shù)據(jù)保存到數(shù)據(jù)庫。
var saveone Userinfo
saveone.Username = "Test Add User"
saveone.Departname = "Test Add Departname"
saveone.Created = time.Now()
orm.Save(&saveone)
我們看到插入之后saveone.Uid就是插入成功之后的自增ID。Save接口會自動幫你存進(jìn)去。
beedb接口提供了另外一種插入的方式,map數(shù)據(jù)插入。
add := make(map[string]interface{})
add["username"] = "astaxie"
add["departname"] = "cloud develop"
add["created"] = "2012-12-02"
orm.SetTable("userinfo").Insert(add)
插入多條數(shù)據(jù)
addslice := make([]map[string]interface{}, 0)
add:=make(map[string]interface{})
add2:=make(map[string]interface{})
add["username"] = "astaxie"
add["departname"] = "cloud develop"
add["created"] = "2012-12-02"
add2["username"] = "astaxie2"
add2["departname"] = "cloud develop2"
add2["created"] = "2012-12-02"
addslice =append(addslice, add, add2)
orm.SetTable("userinfo").InsertBatch(addslice)
上面的操作方式有點(diǎn)類似鏈?zhǔn)讲樵儯煜query的同學(xué)應(yīng)該會覺得很親切,每次調(diào)用的method都會返回原orm對象,以便可以繼續(xù)調(diào)用該對象上的其他method。
上面我們調(diào)用的SetTable函數(shù)是顯式的告訴ORM,我要執(zhí)行的這個(gè)map對應(yīng)的數(shù)據(jù)庫表是userinfo。
繼續(xù)上面的例子來演示更新操作,現(xiàn)在saveone的主鍵已經(jīng)有值了,此時(shí)調(diào)用save接口,beedb內(nèi)部會自動調(diào)用update以進(jìn)行數(shù)據(jù)的更新而非插入操作。
saveone.Username = "Update Username"
saveone.Departname = "Update Departname"
saveone.Created = time.Now()
orm.Save(&saveone) //現(xiàn)在saveone有了主鍵值,就執(zhí)行更新操作
更新數(shù)據(jù)也支持直接使用map操作
t := make(map[string]interface{})
t["username"] = "astaxie"
orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)
這里我們調(diào)用了幾個(gè)beedb的函數(shù)
SetPK:顯式的告訴ORM,數(shù)據(jù)庫表userinfo的主鍵是uid。
Where:用來設(shè)置條件,支持多個(gè)參數(shù),第一個(gè)參數(shù)如果為整數(shù),相當(dāng)于調(diào)用了Where("主鍵=?",值)。 Updata函數(shù)接收map類型的數(shù)據(jù),執(zhí)行更新數(shù)據(jù)。
beedb的查詢接口比較靈活,具體使用請看下面的例子
例子1,根據(jù)主鍵獲取數(shù)據(jù):
var user Userinfo
//Where接受兩個(gè)參數(shù),支持整形參數(shù)
orm.Where("uid=?", 27).Find(&user)
例子2:
var user2 Userinfo
orm.Where(3).Find(&user2) // 這是上面版本的縮寫版,可以省略主鍵
例子3,不是主鍵類型的的條件:
var user3 Userinfo
//Where接受兩個(gè)參數(shù),支持字符型的參數(shù)
orm.Where("name = ?", "john").Find(&user3)
例子4,更加復(fù)雜的條件:
var user4 Userinfo
//Where支持三個(gè)參數(shù)
orm.Where("name = ? and age < ?", "john", 88).Find(&user4)
可以通過如下接口獲取多條數(shù)據(jù),請看示例
例子1,根據(jù)條件id>3,獲取20位置開始的10條數(shù)據(jù)的數(shù)據(jù)
var allusers []Userinfo
err := orm.Where("id > ?", "3").Limit(10,20).FindAll(&allusers)
例子2,省略limit第二個(gè)參數(shù),默認(rèn)從0開始,獲取10條數(shù)據(jù)
var tenusers []Userinfo
err := orm.Where("id > ?", "3").Limit(10).FindAll(&tenusers)
例子3,獲取全部數(shù)據(jù)
var everyone []Userinfo
err := orm.OrderBy("uid desc,username asc").FindAll(&everyone)
上面這些里面里面我們看到一個(gè)函數(shù)Limit,他是用來控制查詢結(jié)構(gòu)條數(shù)的。
Limit:支持兩個(gè)參數(shù),第一個(gè)參數(shù)表示查詢的條數(shù),第二個(gè)參數(shù)表示讀取數(shù)據(jù)的起始位置,默認(rèn)為0。
OrderBy:這個(gè)函數(shù)用來進(jìn)行查詢排序,參數(shù)是需要排序的條件。
上面這些例子都是將獲取的的數(shù)據(jù)直接映射成struct對象,如果我們只是想獲取一些數(shù)據(jù)到map,以下方式可以實(shí)現(xiàn):
a, _ := orm.SetTable("userinfo").SetPK("uid").Where(2).Select("uid,username").FindMap()
上面和這個(gè)例子里面又出現(xiàn)了一個(gè)新的接口函數(shù)Select,這個(gè)函數(shù)用來指定需要查詢多少個(gè)字段。默認(rèn)為全部字段*。
FindMap()函數(shù)返回的是[]map[string][]byte類型,所以你需要自己作類型轉(zhuǎn)換。
beedb提供了豐富的刪除數(shù)據(jù)接口,請看下面的例子
例子1,刪除單條數(shù)據(jù)
//saveone就是上面示例中的那個(gè)saveone
orm.Delete(&saveone)
例子2,刪除多條數(shù)據(jù)
//alluser就是上面定義的獲取多條數(shù)據(jù)的slice
orm.DeleteAll(&alluser)
例子3,根據(jù)sql刪除數(shù)據(jù)
orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow()
目前beedb還不支持struct的關(guān)聯(lián)關(guān)系,但是有些應(yīng)用卻需要用到連接查詢,所以現(xiàn)在beedb提供了一個(gè)簡陋的實(shí)現(xiàn)方案:
a, _ := orm.SetTable("userinfo").Join("LEFT", "userdeatail", "userinfo.uid=userdeatail.uid").Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdeatail.profile").FindMap()
上面代碼中我們看到了一個(gè)新的接口Join函數(shù),這個(gè)函數(shù)帶有三個(gè)參數(shù)
針對有些應(yīng)用需要用到group by和having的功能,beedb也提供了一個(gè)簡陋的實(shí)現(xiàn)
a, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='astaxie'").FindMap()
上面的代碼中出現(xiàn)了兩個(gè)新接口函數(shù)
GroupBy:用來指定進(jìn)行g(shù)roupby的字段
Having:用來指定having執(zhí)行的時(shí)候的條件
目前beedb已經(jīng)獲得了很多來自國內(nèi)外用戶的反饋,我目前也正在考慮重構(gòu),接下來會在幾個(gè)方面進(jìn)行改進(jìn)
實(shí)現(xiàn)關(guān)聯(lián)數(shù)據(jù)庫設(shè)計(jì),支持一對一,一對多,多對多的實(shí)現(xiàn),示例代碼如下:
type Profile struct{ Nickname string Mobile string }
type Userinfo struct {
Uid int PK
Username string
Departname string
Created time.Time
Profile HasOne
}