Merging other languages

This commit is contained in:
James Miranda
2016-09-23 18:01:10 -03:00
parent 380a8ee74c
commit de3c5bdaa4
490 changed files with 24539 additions and 24588 deletions

View File

@@ -1,249 +1,256 @@
# 5.5 使用beedb库进行ORM开发
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[*]
## 安装
beedb支持go get方式安装是完全按照Go Style的方式来实现的。
go get github.com/astaxie/beedb
## 如何初始化
首先你需要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`,字段命名也遵循该规则。
## 插入数据
下面的代码演示了如何插入一条记录可以看到我们操作的是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`
## 更新数据
继续上面的例子来演示更新操作现在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类型的数据执行更新数据。
## 查询数据
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`类型,所以你需要自己作类型转换。
## 删除数据
beedb提供了丰富的删除数据接口请看下面的例子
例子1删除单条数据
//saveone就是上面示例中的那个saveone
orm.Delete(&saveone)
例子2删除多条数据
//alluser就是上面定义的获取多条数据的slice
orm.DeleteAll(&alluser)
例子3根据sql删除数据
orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow()
## 关联查询
目前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等
- 第二个参数表示连接的表
- 第三个参数表示连接的条件
## Group By和Having
针对有些应用需要用到group by和having的功能beedb也提供了一个简陋的实现
a, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='astaxie'").FindMap()
上面的代码中出现了两个新接口函数
GroupBy:用来指定进行groupby的字段
Having:用来指定having执行的时候的条件
## 进一步的发展
目前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
## links
* [目录](<preface.md>)
* 上一节: [使用PostgreSQL数据库](<05.4.md>)
* 下一节: [NOSQL数据库操作](<05.6.md>)
# 5.5 Develop ORM based on beedb
( ***Project beedb is no longer maintained, but the code s still there*** )
beedb is an ORM ( object-relational mapper ) developed in Go, by me.
It uses idiomatic Go to operate on databases, implementing struct to database mapping and acts as a lightweight Go ORM framework. The purpose of developing this ORM is not only to help people learn how to write an ORM, but also to find a good balance between functionality and performance when it comes to data persistence.
beedb is an open source project that supports basic ORM functionality, but doesn't support association queries.
Because beedb supports `database/sql` interface standards, any driver that implements this interface can be used with beedb. I've tested the following drivers:
Mysql: [github.com/ziutek/mymysql/godrv](github.com/ziutek/mymysql/godrv)
Mysql: [code.google.com/p/go-mysql-driver](code.google.com/p/go-mysql-driver)
PostgreSQL: [github.com/bmizerany/pq](github.com/bmizerany/pq)
SQLite: [github.com/mattn/go-sqlite3](github.com/mattn/go-sqlite3)
MS ADODB: [github.com/mattn/go-adodb](github.com/mattn/go-adodb)
ODBC: [bitbucket.org/miquella/mgodbc](bitbucket.org/miquella/mgodbc)
## Installation
You can use `go get` to install beedb locally.
go get github.com/astaxie/beedb
## Initialization
First, you have to import all the necessary packages:
import (
"database/sql"
"github.com/astaxie/beedb"
_ "github.com/ziutek/mymysql/godrv"
)
Then you need to open a database connection and create a beedb object (MySQL in this example):
db, err := sql.Open("mymysql", "test/xiemengjun/123456")
if err != nil {
panic(err)
}
orm := beedb.New(db)
`beedb.New()` actually has two arguments. The first is the the database opject, and the second is for indicating which database engine you're using. If you're using MySQL/SQLite, you can just skip the second argument.
Otherwise, this argument must be supplied. For instance, in the case of SQLServer:
orm = beedb.New(db, "mssql")
PostgreSQL:
orm = beedb.New(db, "pg")
beedb supports debugging. Use the following code to enable it:
beedb.OnDebug=true
Next, we have a struct for the `Userinfo` database table that we used in previous sections.
type Userinfo struct {
Uid int `PK` // if the primary key is not id, you need to add tag `PK` for your customized primary key.
Username string
Departname string
Created time.Time
}
Be aware that beedb auto-converts camelcase names to lower snake case. For example, if we have `UserInfo` as the struct name, beedb will convert it to `user_info` in the database. The same rule applies to struct field names.
Camel
## Insert data
The following example shows you how to use beedb to save a struct, instead of using raw SQL commands. We use the beedb Save method to apply the change.
var saveone Userinfo
saveone.Username = "Test Add User"
saveone.Departname = "Test Add Departname"
saveone.Created = time.Now()
orm.Save(&saveone)
You can check `saveone.Uid` after the record is inserted; its value is a self-incremented ID, which the Save method takes care of for you.
beedb provides another way of inserting data; this is via Go's map type.
add := make(map[string]interface{})
add["username"] = "astaxie"
add["departname"] = "cloud develop"
add["created"] = "2012-12-02"
orm.SetTable("userinfo").Insert(add)
Insert multiple data:
addslice := make([]map[string]interface{}, 10)
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)
The method shown above is similar to a chained query, which you should be familiar with if you've ever used jquery. It returns the original ORM object after calls, then continues doing other jobs.
The method `SetTable` tells the ORM we want to insert our data into the `userinfo` table.
## Update data
Let's continue working with the above example to see how to update data. Now that we have the primary key of saveone(Uid), beedb executes an update operation instead of inserting a new record.
saveone.Username = "Update Username"
saveone.Departname = "Update Departname"
saveone.Created = time.Now()
orm.Save(&saveone) // update
Like before, you can use map for updating data also:
t := make(map[string]interface{})
t["username"] = "astaxie"
orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)
Let me explain some of the methods used above:
- `.SetPK()` tells the ORM that `uid` is the primary key records in the `userinfo` table.
- `.Where()` sets conditions and supports multiple arguments. If the first argument is an integer, it's a short form for `Where("<primary key>=?", <value>)`.
- `.Update()` method accepts a map and updates the database.
## Query data
The beedb query interface is very flexible. Let's see some examples:
Example 1, query by primary key:
var user Userinfo
// Where accepts two arguments, supports integers
orm.Where("uid=?", 27).Find(&user)
Example 2:
var user2 Userinfo
orm.Where(3).Find(&user2) // short form that omits primary key
Example 3, other query conditions:
var user3 Userinfo
// Where accepts two arguments, supports char type.
orm.Where("name = ?", "john").Find(&user3)
Example 4, more complex conditions:
var user4 Userinfo
// Where accepts three arguments
orm.Where("name = ? and age < ?", "john", 88).Find(&user4)
Examples to get multiple records:
Example 1, gets 10 records with `id>3` that starts with position 20:
var allusers []Userinfo
err := orm.Where("id > ?", "3").Limit(10,20).FindAll(&allusers)
Example 2, omits the second argument of limit, so it starts with 0 and gets 10 records:
var tenusers []Userinfo
err := orm.Where("id > ?", "3").Limit(10).FindAll(&tenusers)
Example 3, gets all records:
var everyone []Userinfo
err := orm.OrderBy("uid desc,username asc").FindAll(&everyone)
As you can see, the Limit method is for limiting the number of results.
- `.Limit()` supports two arguments: the number of results and the starting position. 0 is the default value of the starting position.
- `.OrderBy()` is for ordering results. The argument is the order condition.
All the examples here are simply mapping records to structs. You can also just put the data into a map as follows:
a, _ := orm.SetTable("userinfo").SetPK("uid").Where(2).Select("uid,username").FindMap()
- `.Select()` tells beedb how many fields you want to get from the database table. If unspecified, all fields are returned by default.
- `.FindMap()` returns the `[]map[string][]byte` type, so you need to convert to other types yourself.
## Delete data
beedb provides rich methods to delete data.
Example 1, delete a single record:
// saveone is the one in above example.
orm.Delete(&saveone)
Example 2, delete multiple records:
// alluser is the slice which gets multiple records.
orm.DeleteAll(&alluser)
Example 3, delete records by SQL:
orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow()
## Association queries
beedb doesn't support joining between structs.
However, since some applications need this feature, here is an implementation:
a, _ := orm.SetTable("userinfo").Join("LEFT", "userdetail", "userinfo.uid=userdetail.uid")
.Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdetail.profile").FindMap()
We see a new method called `.Join()` that has three arguments:
- The first argument: Type of Join; INNER, LEFT, OUTER, CROSS, etc.
- The second argument: the table you want to join with.
- The third argument: join condition.
## Group By and Having
beedb also has an implementation of `group by` and `having`.
a, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='astaxie'").FindMap()
- `.GroupBy()` indicates the field that is for group by.
- `.Having()` indicates conditions of having.
## Future
I have received a lot of feedback on beedb from many people all around world, and I'm thinking about reconfiguring the following aspects:
- Implement an interface design similar to `database/sql/driver` in order to facilitate CRUD operations.
- Implement relational database associations like one to one, one to many and many to many. Here's a sample:
type Profile struct {
Nickname string
Mobile string
}
type Userinfo struct {
Uid int
PK_Username string
Departname string
Created time.Time
Profile HasOne
}
- Auto-create tables and indexes.
- Implement a connection pool using goroutines.
## Links
- [Directory](preface.md)
- Previous section: [PostgreSQL](05.4.md)
- Next section: [NoSQL database](05.6.md)