New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xorm - 课时 1:常见用法指导 #3

Open
Unknwon opened this Issue Nov 22, 2016 · 0 comments

Comments

1 participant
@Unknwon
Owner

Unknwon commented Nov 22, 2016

日期:2014-04-04
更新:2015-11-11

注意事项

本博客隶属于 xorm - 课时 1:常见用法指导 请注意配套使用。

本博文为 xorm - Go 语言 ORM 的配套博客,旨在通过文字结合代码示例对该库的使用方法和案例进行讲解,便于各位同学更好地使用和深入了解。

库简介

xorm 是一款针对 Go 语言的 ORM 第三方库,特点是提供简单但丰富实用的 API 来完成对数据库的各类操作。该库支持包括 MySQL、PostgreSQL、SQLite3 和 MsSQL 在内的主流数据库,其在支持链式操作的基础上,还允许结合 SQL 语句进行混合处理。另外,支持 session 事务和回滚以及乐观锁也是使得该库逐渐流行的原因之一。

下载安装

您可以通过以下两种方式下载安装 xorm:

gopm get github.com/go-xorm/xorm

go get github.com/go-xorm/xorm

API 文档

请移步 Go Walker

基本使用方法

示例代码

定义模型

在使用 Go 语言的 ORM 之前,都需要对模型进行定义。对于 Go 语言而言,通过定义一个结构体(struct)和该结构体的字段的类型与 tag 来完成对模型的定义。例如,在本课时的例子中,我们就通过以下代码来定义一个银行账户的模型:

type Account struct {
	Id      int64
	Name    string `xorm:"unique"`
	Balance float64
	Version int `xorm:"version"` // 乐观锁
}

由于关系型数据库涉及到主键问题,为了方便用户的使用,凡是类型为 int64 且字段名为 Id 且没有定义任何 tag 的字段,都会自动被认为是主键。如果您想要采用其它名称为主键,则可以在 tag 中设置 pk 来告知 xorm。

字段 Name 的 tag 使用了 unique 则表示该字段记录的值在整个数据表中是唯一的,不能够出现重复的用户名。

最后一行的乐观锁暂不深入,后文会讲到。

在定义模型时需要注意的是所有字段的首字母必须是大写的(Go 语言的导出规则),否则 ORM 是无法通过反射获取到字段的名称和类型,可能会引发 panic。

由于例子比较简单,并不能够列举出所有 xorm 支持的 tag 定义,完整的列表可以查看 这里

创建 ORM 引擎

在完成模型定义之后,我们就需要创建 ORM 的引擎了。在创建 ORM 引擎这个步骤时,您需要确定您所使用的数据库驱动以及相关的链接信息(数据库 HOST、用户、密码等)。本例采用的是 SQLite3,所以只需要指定数据库文件所在的路径就可以了:

x, err = xorm.NewEngine("sqlite3", "./bank.db")

Go 语言要求所使用的数据库驱动必须注册之后才能使用,因此所有的驱动库都会在 init 函数中对自身进行注册,以便我们在使用时候不会出现错误。同样地,使用 ORM 也是需要对我们所使用的数据库驱动进行注册,那么如何注册呢?

由于数据库驱动的种类较多,一般每个 ORM 都只会对一种数据库选择一个驱动进行支持,所以在注册驱动之前,需要确认一下您所使用的 ORM 是否支持您所选的驱动。比如 xorm 就支持多达 5 种数据库驱动

注册数据库驱动的方法如下:

import (
	_ "github.com/mattn/go-sqlite3"
)

很多同学看到导入路径前面的 _ 下划线表示不解,这是没有学习好无闻出品的 《Go编程基础》 的恶果。在导入路径前加入下划线表示只执行该库的 init 函数而不对其它导出对象进行真正地导入。因为 Go 语言的数据库驱动都会在 init 函数中注册自己,所以我们只需要进行上述操作即可;否则的话,Go 语言的编译器会提示导入了包却没有使用的错误。

自动同步表结构

xorm 有一个非常赞的功能,就是支持自动增量同步数据表结构。什么意思呢?就是在您完成数据库的创建之后,ORM 会自动根据所定义的模型来自动创建数据表,这就是为什么我们需要使用 tag 来对字段进行一些特别的指定(例如:unique)。所谓增量同步,就是指只会对新增的字段或 tag 定义进行同步,包括新定义的模型、字段和 tag 规则;如果您删除或修改了某个字段,出于安全考虑,已经创建的列(column)是不会被删除或修改的,而是直接忽略或新建修改后的列。

通过下面的方法,就能够调用 xorm 提供的自动同步数据表结构的功能:

err = x.Sync(new(Account))

方法 Sync 需要传入所有您将会用到的模型,本例中只有 Account。之所以使用 new() 方法进行一次创建对象是因为 ORM 的解析结构体的工作都是通过反射完成的,只有传递一个实例对象才能够让 ORM 获取到相应的字段和 tag。

增、删、改操作

首先,我们来看看如何使用 xorm 实现最基本的增、删、改操作。

新增记录

插入一条新的记录,该记录必须是未存在的,否则会返回错误:

_, err := x.Insert(&Account{Name: name, Balance: balance})

删除记录

删除一条记录:

_, err := x.Delete(&Account{Id: id})

方法 Delete 接受参数后,会自动根据传进去的值进行查找,然后删除。比如此处,我们指定了 Account 的 ID 字段,那么就会删除 ID 字段值与我们所赋值相同的记录;如果您只对 Name 字段赋值,那么 xorm 就会去查找 Name 字段值匹配的记录。如果多个字段同时赋值,则是多个条件同时满足的记录才会被删除。

删除操作针对的对象没有限制,凡是按照条件查找到的,都会被删除(单个与批量删除)。

获取与修改记录

根据 xorm 的要求,想要更新一条记录则该记录必须是已存在的,所以我们需要先获取记录的相应信息,然后做修改,最后进行更新:

a := &Account{}
has, err := x.Id(id).Get(a)

方法 Get 只会返回单个记录,与删除操作类似的,任何对于变量 a 的赋值就会变成查找条件。但 xorm 的灵活之处在于,您还可以通过链式操作方便的达到同样的需求。正如本例中直接使用 Id 方法来获取指定 ID 的记录一样。

该方法会返回两个值,第一个为 bool 类型,表示是否查找到记录;第二个为 error 类型,表示是否发生其它错误。

在获取到记录之后,我们就需要进行一些修改,然后更新到数据库:

a.Balance += deposit
// 对已有记录进行更新
_, err = x.Update(a)

方法 Update 接受的第一个参数必须是指针地址,指向需要更新的内容。此外,它还允许接收第二个参数,与之前在删除和获取操作中提到的条件查询作用相同,如果您传入了第二个参数,则会根据参数进行条件筛选,然后更新相应的字段。

批量获取信息

除了对单个记录进行获取之外,为了能够更好的查看内容,有时我们会需要一次性取出多条记录,并进行一定的排序。

因此,与获取单个记录的 Get 方法相对应的是获取所有符合条件的记录的 Find 方法:

err = x.Desc("balance").Find(&as)

在这里,我们还调用了 Desc 方法对记录按照存款数额将账户从大到小排序。

方法 Find 接受的第一个参数必须是某个类型的 slice 的指针地址,本例中使用的是元素类型为 Account 类型的 slice 的指针地址;它的第二个参数也是条件参数,作用前文已经详细描述。

乐观锁

乐观锁是 xorm 提供的一个比较实用的功能,通过在 tag 中指定 version 来开启它。开启之后,每次对记录进行更新的时候,该字段的值就会自动递增 1。如此一来,您就可以判断是否有其它地方同时修改了该记录,如果是,则应当重新操作,否则会出现错误的数据(同时对一个帐号进行取款操作却只扣了一次的数额)。

小结

本课时只是针对 xorm 的讲解的第一课时,在代码实现上追求基础、直观,并未涉及到非常多的内容,以免让新手显得迷茫。所以,本例中的代码实际上是存在一些缺陷的,比如说在转账就应该使用事务以便发生错误时进行回滚,以免转账失败时转账双方都没有回归到原有的数额。

@Unknwon Unknwon added Go XORM labels Nov 22, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment