beedb是我開發的一個Go進行ORM操作的庫,它采用了Go style方式對數據庫進行操作,實現了struct到數據表記錄的映射。beedb是一個十分輕量級的Go ORM框架,開發這個庫的本意降低復雜的ORM學習曲線,盡可能在ORM的運行效率和功能之間尋求一個平衡,beedb是目前開源的Go ORM框架中實現比較完整的一個庫,而且運行效率相當不錯,功能也基本能滿足需求。但是目前還不支持關系關聯,這個是接下來版本升級的重點。
beedb是支持database/sql標準接口的ORM庫,所以理論上來說,只要數據庫驅動支持database/sql接口就可以無縫的接入beedb。目前我測試過的驅動包括下面幾個:
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[*]
## [](https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/05.5.md#安裝)安裝
beedb支持go get方式安裝,是完全按照Go Style的方式來實現的。
~~~
go get github.com/astaxie/beedb
~~~
## [](https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/05.5.md#如何初始化)如何初始化
首先你需要import相應的數據庫驅動包、database/sql標準接口包以及beedb包,如下所示:
~~~
import (
"database/sql"
"github.com/astaxie/beedb"
_ "github.com/ziutek/mymysql/godrv"
)
~~~
導入必須的package之后,我們需要打開到數據庫的鏈接,然后創建一個beedb對象(以MySQL為例),如下所示
~~~
db, err := sql.Open("mymysql", "test/xiemengjun/123456")
if err != nil {
panic(err)
}
orm := beedb.New(db)
~~~
beedb的New函數實際上應該有兩個參數,第一個參數標準接口的db,第二個參數是使用的數據庫引擎,如果你使用的數據庫引擎是MySQL/Sqlite,那么第二個參數都可以省略。
如果你使用的數據庫是SQLServer,那么初始化需要:
~~~
orm = beedb.New(db, "mssql")
~~~
如果你使用了PostgreSQL,那么初始化需要:
~~~
orm = beedb.New(db, "pg")
~~~
目前beedb支持打印調試,你可以通過如下的代碼實現調試
~~~
beedb.OnDebug=true
~~~
接下來我們的例子采用前面的數據庫表Userinfo,現在我們建立相應的struct
~~~
type Userinfo struct {
Uid int `PK` //如果表的主鍵不是id,那么需要加上pk注釋,顯式的說這個字段是主鍵
Username string
Departname string
Created time.Time
}
~~~
> 注意一點,beedb針對駝峰命名會自動幫你轉化成下劃線字段,例如你定義了Struct名字為`UserInfo`,那么轉化成底層實現的時候是`user_info`,字段命名也遵循該規則。
## [](https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/05.5.md#插入數據)插入數據
下面的代碼演示了如何插入一條記錄,可以看到我們操作的是struct對象,而不是原生的sql語句,最后通過調用Save接口將數據保存到數據庫。
~~~
var saveone Userinfo
saveone.Username = "Test Add User"
saveone.Departname = "Test Add Departname"
saveone.Created = time.Now()
orm.Save(&saveone)
~~~
我們看到插入之后`saveone.Uid`就是插入成功之后的自增ID。Save接口會自動幫你存進去。
beedb接口提供了另外一種插入的方式,map數據插入。
~~~
add := make(map[string]interface{})
add["username"] = "astaxie"
add["departname"] = "cloud develop"
add["created"] = "2012-12-02"
orm.SetTable("userinfo").Insert(add)
~~~
插入多條數據
~~~
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)
~~~
上面的操作方式有點類似鏈式查詢,熟悉jquery的同學應該會覺得很親切,每次調用的method都會返回原orm對象,以便可以繼續調用該對象上的其他method。
上面我們調用的SetTable函數是顯式的告訴ORM,我要執行的這個map對應的數據庫表是`userinfo`。
## [](https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/05.5.md#更新數據)更新數據
繼續上面的例子來演示更新操作,現在saveone的主鍵已經有值了,此時調用save接口,beedb內部會自動調用update以進行數據的更新而非插入操作。
~~~
saveone.Username = "Update Username"
saveone.Departname = "Update Departname"
saveone.Created = time.Now()
orm.Save(&saveone) //現在saveone有了主鍵值,就執行更新操作
~~~
更新數據也支持直接使用map操作
~~~
t := make(map[string]interface{})
t["username"] = "astaxie"
orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)
~~~
這里我們調用了幾個beedb的函數
SetPK:顯式的告訴ORM,數據庫表`userinfo`的主鍵是`uid`。
Where:用來設置條件,支持多個參數,第一個參數如果為整數,相當于調用了Where("主鍵=?",值)。 Updata函數接收map類型的數據,執行更新數據。
## [](https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/05.5.md#查詢數據)查詢數據
beedb的查詢接口比較靈活,具體使用請看下面的例子
例子1,根據主鍵獲取數據:
~~~
var user Userinfo
//Where接受兩個參數,支持整形參數
orm.Where("uid=?", 27).Find(&user)
~~~
例子2:
~~~
var user2 Userinfo
orm.Where(3).Find(&user2) // 這是上面版本的縮寫版,可以省略主鍵
~~~
例子3,不是主鍵類型的的條件:
~~~
var user3 Userinfo
//Where接受兩個參數,支持字符型的參數
orm.Where("name = ?", "john").Find(&user3)
~~~
例子4,更加復雜的條件:
~~~
var user4 Userinfo
//Where支持三個參數
orm.Where("name = ? and age < ?", "john", 88).Find(&user4)
~~~
可以通過如下接口獲取多條數據,請看示例
例子1,根據條件id>3,獲取20位置開始的10條數據的數據
~~~
var allusers []Userinfo
err := orm.Where("id > ?", "3").Limit(10,20).FindAll(&allusers)
~~~
例子2,省略limit第二個參數,默認從0開始,獲取10條數據
~~~
var tenusers []Userinfo
err := orm.Where("id > ?", "3").Limit(10).FindAll(&tenusers)
~~~
例子3,獲取全部數據
~~~
var everyone []Userinfo
err := orm.OrderBy("uid desc,username asc").FindAll(&everyone)
~~~
上面這些里面里面我們看到一個函數Limit,他是用來控制查詢結構條數的。
Limit:支持兩個參數,第一個參數表示查詢的條數,第二個參數表示讀取數據的起始位置,默認為0。
OrderBy:這個函數用來進行查詢排序,參數是需要排序的條件。
上面這些例子都是將獲取的的數據直接映射成struct對象,如果我們只是想獲取一些數據到map,以下方式可以實現:
~~~
a, _ := orm.SetTable("userinfo").SetPK("uid").Where(2).Select("uid,username").FindMap()
~~~
上面和這個例子里面又出現了一個新的接口函數Select,這個函數用來指定需要查詢多少個字段。默認為全部字段`*`。
FindMap()函數返回的是`[]map[string][]byte`類型,所以你需要自己作類型轉換。
## [](https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/05.5.md#刪除數據)刪除數據
beedb提供了豐富的刪除數據接口,請看下面的例子
例子1,刪除單條數據
~~~
//saveone就是上面示例中的那個saveone
orm.Delete(&saveone)
~~~
例子2,刪除多條數據
~~~
//alluser就是上面定義的獲取多條數據的slice
orm.DeleteAll(&alluser)
~~~
例子3,根據sql刪除數據
~~~
orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow()
~~~
## [](https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/05.5.md#關聯查詢)關聯查詢
目前beedb還不支持struct的關聯關系,但是有些應用卻需要用到連接查詢,所以現在beedb提供了一個簡陋的實現方案:
~~~
a, _ := orm.SetTable("userinfo").Join("LEFT", "userdeatail", "userinfo.uid=userdeatail.uid").Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdeatail.profile").FindMap()
~~~
上面代碼中我們看到了一個新的接口Join函數,這個函數帶有三個參數
* 第一個參數可以是:INNER, LEFT, OUTER, CROSS等
* 第二個參數表示連接的表
* 第三個參數表示連接的條件
## [](https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/05.5.md#group-by和having)Group By和Having
針對有些應用需要用到group by和having的功能,beedb也提供了一個簡陋的實現
~~~
a, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='astaxie'").FindMap()
~~~
上面的代碼中出現了兩個新接口函數
GroupBy:用來指定進行groupby的字段
Having:用來指定having執行的時候的條件
## [](https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/05.5.md#進一步的發展)進一步的發展
目前beedb已經獲得了很多來自國內外用戶的反饋,我目前也正在考慮重構,接下來會在幾個方面進行改進
* 實現interface設計,類似databse/sql/driver的設計,設計beedb的接口,然后去實現相應數據庫的CRUD操作
* 實現關聯數據庫設計,支持一對一,一對多,多對多的實現,示例代碼如下:
type Profile struct{ Nickname string Mobile string }
type Userinfo struct { Uid int?`PK`?Username string Departname string Created time.Time Profile?`HasOne`?}
* 自動建庫建表建索引
* 實現連接池的實現,采用goroutine
- 第一章 Go環境配置
- 1.1 Go安裝
- 1.2 GOPATH 與工作空間
- 1.3 Go 命令
- 1.4 Go開發工具
- 1.5 小結
- 第二章 Go語言基礎
- 2.1 你好,Go
- 2.2 Go基礎
- 2.3 流程和函數
- 2.4 struct類型
- 2.5 面向對象
- 2.6 interface
- 2.7 并發
- 2.8 總結
- 第三章 Web基礎
- 3.1 Web工作方式
- 3.2 Go搭建一個Web服務器
- 3.3 Go如何使得Web工作
- 3.4 Go的http包詳解
- 3.5 小結
- 第四章 表單
- 4.1 處理表單的輸入
- 4.2 驗證表單的輸入
- 4.3 預防跨站腳本
- 4.4 防止多次遞交表單
- 4.5 處理文件上傳
- 4.6 小結
- 第五章 訪問數據庫
- 5.1 database/sql接口
- 5.2 使用MySQL數據庫
- 5.3 使用SQLite數據庫
- 5.4 使用PostgreSQL數據庫
- 5.5 使用beedb庫進行ORM開發
- 5.6 NOSQL數據庫操作
- 5.7 小結
- 第六章 session和數據存儲
- 6.1 session和cookie
- 6.2 Go如何使用session
- 6.3 session存儲
- 6.4 預防session劫持
- 6.5 小結
- 第七章 文本處理
- 7.1 XML處理
- 7.2 JSON處理
- 7.3 正則處理
- 7.4 模板處理
- 7.5 文件操作
- 7.6 字符串處理
- 7.7 小結
- 第八章 Web服務
- 8.1 Socket編程
- 8.2 WebSocket
- 8.3 REST
- 8.4 RPC
- 8.5 小結
- 第九章 安全與加密
- 9.1 預防CSRF攻擊
- 9.2 確保輸入過濾
- 9.3 避免XSS攻擊
- 9.4 避免SQL注入
- 9.5 存儲密碼
- 9.6 加密和解密數據
- 9.7 小結
- 第十章 國際化和本地化
- 10.1 設置默認地區
- 10.2 本地化資源
- 10.3 國際化站點
- 10.4 小結
- 第十一章 錯誤處理,調試和測試
- 11.1 錯誤處理
- 11.2 使用GDB調試
- 11.3 Go怎么寫測試用例
- 11.4 小結
- 第十二章 部署與維護
- 12.1 應用日志
- 12.2 網站錯誤處理
- 12.3 應用部署
- 12.4 備份和恢復
- 12.5 小結
- 第十三章 如何設計一個Web框架
- 13.1 項目規劃
- 13.2 自定義路由器設計
- 13.3 controller設計
- 13.4 日志和配置設計
- 13.5 實現博客的增刪改
- 13.6 小結
- 第十四章 擴展Web框架
- 14.1 靜態文件支持
- 14.2 Session支持
- 14.3 表單及驗證支持
- 14.4 用戶認證
- 14.5 多語言支持
- 14.6 pprof支持
- 14.7 小結
- 附錄A 參考資料