Files
build-web-application-with-…/zh-tw/05.5.md
2019-02-26 01:40:54 +08:00

11 KiB
Raw Blame History

5.5 使用Beego orm函式庫進行ORM開發

beego orm是我開發的一個Go進行ORM操作的函式庫它採用了Go style方式對資料庫進行操作實現了struct到資料表記錄的對映。beego orm是一個十分輕量級的Go ORM框架開發這個函式庫的本意降低複雜的ORM學習曲線儘可能在ORM的執行效率和功能之間尋求一個平衡beego orm是目前開源的Go ORM框架中實現比較完整的一個函式庫而且執行效率相當不錯功能也基本能滿足需求。

beego orm是支援database/sql標準介面的ORM函式庫所以理論上來說只要資料庫驅動支援database/sql介面就可以無縫的接入beego orm。目前我測試過的驅動包括下面幾個

Mysql: github/go-mysql-driver/mysql

PostgreSQL: github.com/lib/pq

SQLite: github.com/mattn/go-sqlite3

Mysql: github.com/ziutek/mymysql/godrv

暫未支援資料庫:

MsSql: github.com/denisenkom/go-mssqldb

MS ADODB: github.com/mattn/go-adodb

Oracle: github.com/mattn/go-oci8

ODBC: bitbucket.org/miquella/mgodbc

安裝

beego orm支援go get方式安裝是完全按照Go Style的方式來實現的。

go get github.com/astaxie/beego

如何初始化

首先你需要import相應的資料庫驅動套件、database/sql標準介面套件以及beego orm套件如下所示


import (
	"database/sql"
	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
)

func init() {
	//註冊驅動
	orm.RegisterDriver("mysql", orm.DR_MySQL)
	//設定預設資料庫
	orm.RegisterDataBase("default", "mysql", "root:root@/my_db?charset=utf8", 30)
	//註冊定義的model
    	orm.RegisterModel(new(User))

   	// 建立table
        orm.RunSyncdb("default", false, true)
}

PostgreSQL 配置:

//匯入驅動
// _ "github.com/lib/pq"

// 註冊驅動
orm.RegisterDriver("postgres", orm.DR_Postgres)

// 設定預設資料庫
//PostgresQL使用者postgres 密碼zxxx  資料庫名稱test  資料庫別名default
orm.RegisterDataBase("default", "postgres", "user=postgres password=zxxx dbname=test host=127.0.0.1 port=5432 sslmode=disable")

MySQL 配置:

//匯入驅動
//_ "github.com/go-sql-driver/mysql"

//註冊驅動
orm.RegisterDriver("mysql", orm.DR_MySQL)

// 設定預設資料庫
//mysql使用者root 密碼zxxx  資料庫名稱test  資料庫別名default
 orm.RegisterDataBase("default", "mysql", "root:zxxx@/test?charset=utf8")

Sqlite 配置:

//匯入驅動
//_ "github.com/mattn/go-sqlite3"

//註冊驅動
orm.RegisterDriver("sqlite", orm.DR_Sqlite)

// 設定預設資料庫
//資料庫存放位置:./datas/test.db  資料庫別名default
orm.RegisterDataBase("default", "sqlite3", "./datas/test.db")

匯入必須的package之後,我們需要開啟到資料庫的連結然後建立一個beego orm物件以MySQL為例),如下所示 beego orm:


func main() {
    	o := orm.NewOrm()
}

簡單示例:


package main

import (
    "fmt"
    "github.com/astaxie/beego/orm"
    _ "github.com/go-sql-driver/mysql" // 匯入資料庫驅動
)

// Model Struct
type User struct {
    Id   int
    Name string `orm:"size(100)"`
}

func init() {
    // 設定預設資料庫
    orm.RegisterDataBase("default", "mysql", "root:root@/my_db?charset=utf8", 30)

    // 註冊定義的 model
    orm.RegisterModel(new(User))
//RegisterModel 也可以同時註冊多個 model
//orm.RegisterModel(new(User), new(Profile), new(Post))

    // 建立 table
    orm.RunSyncdb("default", false, true)
}

func main() {
    o := orm.NewOrm()

    user := User{Name: "slene"}

    // 插入表
    id, err := o.Insert(&user)
    fmt.Printf("ID: %d, ERR: %v\n", id, err)

    // 更新表
    user.Name = "astaxie"
    num, err := o.Update(&user)
    fmt.Printf("NUM: %d, ERR: %v\n", num, err)

    // 讀取 one
    u := User{Id: user.Id}
    err = o.Read(&u)
    fmt.Printf("ERR: %v\n", err)

    // 刪除表
    num, err = o.Delete(&u)
    fmt.Printf("NUM: %d, ERR: %v\n", num, err)
}

SetMaxIdleConns

根據資料庫的別名,設定資料庫的最大空閒連線


orm.SetMaxIdleConns("default", 30)

SetMaxOpenConns

根據資料庫的別名,設定資料庫的最大資料庫連線 (go >= 1.2)


orm.SetMaxOpenConns("default", 30)

目前beego orm支援列印除錯你可以透過如下的程式碼實現除錯


 orm.Debug = true

接下來我們的例子採用前面的資料庫表User現在我們建立相應的struct


type Userinfo struct {
	Uid     int `PK` //如果表的主鍵不是id那麼需要加上pk註釋顯式的說這個欄位是主鍵
	Username    string
	Departname  string
	Created     time.Time
}

type User struct {
	Uid          int `PK` //如果表的主鍵不是id那麼需要加上pk註釋顯式的說這個欄位是主鍵
	Name        string
	Profile     *Profile   `orm:"rel(one)"` // OneToOne relation
	Post        []*Post `orm:"reverse(many)"` // 設定一對多的反向關係
}

type Profile struct {
	Id          int
	Age         int16
	User        *User   `orm:"reverse(one)"` // 設定一對一反向關係(可選)
}

type Post struct {
	Id    int
	Title string
	User  *User  `orm:"rel(fk)"`
	Tags  []*Tag `orm:"rel(m2m)"`    //設定一對多關係
}

type Tag struct {
	Id    int
	Name  string
	Posts []*Post `orm:"reverse(many)"`
}

func init() {
	// 需要在init中註冊定義的model
	orm.RegisterModel(new(Userinfo),new(User), new(Profile), new(Tag))
}


注意一點beego orm針對駝峰命名會自動幫你轉化成下劃線欄位例如你定義了Struct名字為UserInfo,那麼轉化成底層實現的時候是user_info,欄位命名也遵循該規則。

插入資料

下面的程式碼示範瞭如何插入一條記錄可以看到我們操作的是struct物件而不是原生的sql語句最後透過呼叫Insert介面將資料儲存到資料庫。


o := orm.NewOrm()
var user User
user.Name = "zxxx"
user.Departname = "zxxx"

id, err := o.Insert(&user)
if err == nil {
	fmt.Println(id)
}

我們看到插入之後user.Uid就是插入成功之後的自增ID。

同時插入多個物件:InsertMulti

類似sql語句


insert into table (name, age) values("slene", 28),("astaxie", 30),("unknown", 20)

第一個引數 bulk 為並列插入的數量第二個為物件的slice

返回值為成功插入的數量


users := []User{
    {Name: "slene"},
    {Name: "astaxie"},
    {Name: "unknown"},
    ...
}
successNums, err := o.InsertMulti(100, users)

bulk 為 1 時,將會順序插入 slice 中的資料

更新資料

繼續上面的例子來示範更新操作現在user的主鍵已經有值了此時呼叫Insert介面beego orm內部會自動呼叫update以進行資料的更新而非插入操作。


o := orm.NewOrm()
user := User{Uid: 1}
if o.Read(&user) == nil {
	user.Name = "MyName"
	if num, err := o.Update(&user); err == nil {
		fmt.Println(num)
	}
}

Update 預設更新所有的欄位,可以更新指定的欄位:


// 只更新 Name
o.Update(&user, "Name")
// 指定多個欄位
// o.Update(&user, "Field1", "Field2", ...)

//Where:用來設定條件支援多個引數第一個引數如果為整數相當於呼叫了Where("主鍵=?",值)。

查詢資料

beego orm的查詢介面比較靈活具體使用請看下面的例子

例子1根據主鍵取得資料


o := orm.NewOrm()
var user User

user := User{Id: 1}

err = o.Read(&user)

if err == orm.ErrNoRows {
	fmt.Println("查詢不到")
} else if err == orm.ErrMissPK {
	fmt.Println("找不到主鍵")
} else {
	fmt.Println(user.Id, user.Name)
}

例子2


o := orm.NewOrm()
var user User

qs := o.QueryTable(user) // 返回 QuerySeter
qs.Filter("id", 1) // WHERE id = 1
qs.Filter("profile__age", 18) // WHERE profile.age = 18

例子3WHERE IN查詢條件


qs.Filter("profile__age__in", 18, 20)
// WHERE profile.age IN (18, 20)

例子4更加複雜的條件


qs.Filter("profile__age__in", 18, 20).Exclude("profile__lt", 1000)
// WHERE profile.age IN (18, 20) AND NOT profile_id < 1000

可以透過如下介面取得多條資料,請看示例

例子1根據條件age>17取得20位置開始的10條資料的資料


var allusers []User
qs.Filter("profile__age__gt", 17)
// WHERE profile.age > 17

例子2limit預設從10開始取得10條資料


qs.Limit(10, 20)
// LIMIT 10 OFFSET 20 注意跟SQL反過來的

刪除資料

beedb提供了豐富的刪除資料介面請看下面的例子

例子1刪除單條資料


o := orm.NewOrm()
if num, err := o.Delete(&User{Id: 1}); err == nil {
	fmt.Println(num)
}

Delete 操作會對反向關係進行操作,此例中 Post 擁有一個到 User 的外來鍵。刪除 User 的時候。如果 on_delete 設定為預設的級聯操作,將刪除對應的 Post

關聯查詢

有些應用卻需要用到連線查詢所以現在beego orm提供了一個簡陋的實現方案


type Post struct {
	Id    int    `orm:"auto"`
	Title string `orm:"size(100)"`
	User  *User  `orm:"rel(fk)"`
}

var posts []*Post
qs := o.QueryTable("post")
num, err := qs.Filter("User__Name", "slene").All(&posts)

上面程式碼中我們看到了一個struct關聯查詢

Group By和Having

針對有些應用需要用到group by的功能beego orm也提供了一個簡陋的實現


qs.OrderBy("id", "-profile__age")
// ORDER BY id ASC, profile.age DESC

qs.OrderBy("-profile__age", "profile")
// ORDER BY profile.age DESC, profile_id ASC

上面的程式碼中出現了兩個新介面函式

GroupBy:用來指定進行groupby的欄位

Having:用來指定having執行的時候的條件

使用原生sql

簡單示例:


o := orm.NewOrm()
var r orm.RawSeter
r = o.Raw("UPDATE user SET name = ? WHERE name = ?", "testing", "slene")

複雜原生sql使用:

func (m *User) Query(name string) user []User {
	var o orm.Ormer
	var rs orm.RawSeter
	o = orm.NewOrm()
	rs = o.Raw("SELECT * FROM user "+
		"WHERE name=? AND uid>10 "+
		"ORDER BY uid DESC "+
		"LIMIT 100", name)
	//var user []User
	num, err := rs.QueryRows(&user)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(num)
		//return user
	}
	return
}

更多說明,請到beego.me

進一步的發展

目前beego orm已經獲得了很多來自國內外使用者的反饋我目前也正在考慮支援更多資料庫接下來會在更多方面進行改進