更新日志

最后更新于:2022-04-02 01:38:15

### 更新日志 - **v0.4.3** - Json 字段类型支持 - oracle实验性支持 - bug修正 - **v0.4.2** - 事物如未Rollback或Commit,在关闭时会自动Rollback - Gonic 映射支持 - bug修正 - **v0.4.1** - 添加deleted标记作为软删除. - **v0.4.0 RC1** 新特性: - 移动xorm cmd [github.com/go-xorm/cmd](#) - 在重构一般DB操作核心库 [github.com/go-xorm/core](https://github.com/go-xorm/core) - 移动测试github.com/XORM/tests [github.com/go-xorm/tests](#) 改进: - Prepared statement 缓存 - 添加 Incr API - 指定时区位置 - **v0.3.2** 改进: - Add AllCols & MustCols function - Add TableName for custom table name Bug 修复: - # 46 - # 51 - # 53 - # 89 - # 86 - # 92 - **v0.3.1** 新特性: - 支持 MSSQL DB 通过 ODBC 驱动 ([github.com/lunny/godbc](https://github.com/lunny/godbc)); - 通过多个pk标记支持联合主键; - 新增 Rows() API 用来遍历查询结果,该函数提供了类似sql.Rows的相似用法,可作为 Iterate() API 的可选替代; - ORM 结构体现在允许内建类型的指针作为成员,使得数据库为null成为可能; - Before 和 After 支持 改进: - 允许 int/int32/int64/uint/uint32/uint64/string 作为主键类型 - 查询函数 Get()/Find()/Iterate() 在性能上的改进 - **v0.2.3** : 改善了文档;提供了乐观锁支持;添加了带时区时间字段支持;Mapper现在分成表名Mapper和字段名Mapper,同时实现了表或字段的自定义前缀后缀;Insert方法的返回值含义从id, err更改为 affected, err,请大家注意;添加了UseBool 和 Distinct函数。 - **v0.2.2** : Postgres驱动新增了对lib/pq的支持;新增了逐条遍历方法Iterate;新增了SetMaxConns(go1.2+)支持,修复了bug若干; - **v0.2.1** : 新增数据库反转工具,当前支持go和c++代码的生成,详见 [Xorm Tool README](https://github.com/go-xorm/xorm/blob/master/xorm/README.md); 修复了一些bug. - **v0.2.0** : 新增 [缓存](https://github.com/go-xorm/xorm/blob/master/docs/QuickStart.md#120)支持,查询速度提升3-5倍; 新增数据库表和Struct同名的映射方式; 新增Sync同步表结构; - **v0.1.9** : 新增 postgres 和 mymysql 驱动支持; 在Postgres中支持原始SQL语句中使用 ` 和 ? 符号; 新增Cols, StoreEngine, Charset 函数;SQL语句打印支持io.Writer接口,默认打印到控制台;新增更多的字段类型支持,详见 [映射规则](https://github.com/go-xorm/xorm/blob/master/docs/QuickStartCn.md#21);删除废弃的MakeSession和Create函数。 - **v0.1.8** : 新增联合index,联合unique支持,请查看 [映射规则](https://github.com/go-xorm/xorm/blob/master/docs/QuickStartCn.md#21)。 - **v0.1.7** : 新增IConnectPool接口以及NoneConnectPool, SysConnectPool, SimpleConnectPool三种实现,可以选择不使用连接池,使用系统连接池和使用自带连接池三种实现,默认为SysConnectPool,即系统自带的连接池。同时支持自定义连接池。Engine新增Close方法,在系统退出时应调用此方法。 - **v0.1.6** : 新增Conversion,支持自定义类型到数据库类型的转换;新增查询结构体自动检测匿名成员支持;新增单向映射支持; - **v0.1.5** : 新增对多线程的支持;新增Sql()函数;支持任意sql语句的struct查询;Get函数返回值变动;MakeSession和Create函数被NewSession和NewEngine函数替代; - **v0.1.4** : Get函数和Find函数新增简单的级联载入功能;对更多的数据库类型支持。 - **v0.1.3** : Find函数现在支持传入Slice或者Map,当传入Map时,key为id;新增Table函数以为多表和临时表进行支持。 - **v0.1.2** : Insert函数支持混合struct和slice指针传入,并根据数据库类型自动批量插入,同时自动添加事务 - **v0.1.1** : 添加 Id, In 函数,改善 README 文档 - **v0.1.0** : 初始化工程s
';

案例

最后更新于:2022-04-02 01:38:13

### 妗堜緥 - [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs) - [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker) - [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild) - [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress) - [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily) - [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS) - [GoBBS - gobbs.domolo.com](http://gobbs.domolo.com/) - [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog)
';

常见问题

最后更新于:2022-04-02 01:38:10

# 常见问题 - 如何使用Like? 答: ~~~ engine.Where("column like ?", "%"+char+"%").Find ~~~ - 怎么同时使用xorm的tag和json的tag? 答:使用空格 ~~~ type User struct { Name string `json:"name" xorm:"name"` } ~~~ - 我的struct里面包含bool类型,为什么它不能作为条件也没法用Update更新? 答:默认bool类型因为无法判断是否为空,所以不会自动作为条件也不会作为Update的内容。可以使用UseBool函数,也可以使用Cols函数 ~~~ engine.Cols("bool_field").Update(&Struct{BoolField:true}) // UPDATE struct SET bool_field = true ~~~ - 我的struct里面包含float64和float32类型,为什么用他们作为查询条件总是不正确? 答:默认float32和float64映射到数据库中为float,real,double这几种类型,这几种数据库类型数据库的实现一般都是非精确的。因此作为相等条件查询有可能不会返回正确的结果。如果一定要作为查询条件,请将数据库中的类型定义为Numeric或者Decimal。 ~~~ type account struct { money float64 `xorm:"Numeric"` } ~~~ - 为什么Update时Sqlite3返回的affected和其它数据库不一样? 答:Sqlite3默认Update时返回的是update的查询条件的记录数条数,不管记录是否真的有更新。而Mysql和Postgres默认情况下都是只返回记录中有字段改变的记录数。 - xorm有几种命名映射规则? 答:目前支持SnakeMapper和SameMapper两种。SnakeMapper支持结构体和成员以驼峰式命名而数据库表和字段以下划线连接命名;SameMapper支持结构体和数据库的命名保持一致的映射。 - xorm支持复合主键吗? 答:支持。在定义时,如果有多个字段标记了pk,则这些字段自动成为复合主键,顺序为在struct中出现的顺序。在使用Id方法时,可以用`Id(xorm.PK{1, 2})`的方式来用。 - xorm如何使用Join? 答:一般我们配合Join()和extends标记来进行,比如我们要对两个表进行Join操作,我们可以这样: ~~~ type Userinfo struct { Id int64 Name string DetailId int64 } type Userdetail struct { Id int64 Gender int } type User struct { Userinfo `xorm:"extends"` Userdetail `xorm:"extends"` } var users = make([]User, 0) err := engine.Table(&Userinfo{}).Join("LEFT", "userdetail", "userinfo.detail_id = userdetail.id").Find(&users) ~~~ 请注意这里的Userinfo在User中的位置必须在Userdetail的前面,因为他在join语句中的顺序在userdetail前面。如果顺序不对,那么对于同名的列,有可能会赋值出错。 当然,如果Join语句比较复杂,我们也可以直接用Sql函数 ~~~ err := engine.Sql("select * from userinfo, userdetail where userinfo.detail_id = userdetail.id").Find(&users) ~~~ - 如果有自动增长的字段,Insert如何写?答:Insert时,如果需要自增字段填充为自动增长的数值,请保持自增字段为0;如果自增字段为非0,自增字段将会被作为普通字段插入。
';

xorm 工具

最后更新于:2022-04-02 01:38:08

# xorm 工具 xorm 是一组数据库操作命令行工具。 ### 二进制安装 如果你安装了 [got](https://github.com/gobuild/got),你可以输入如下命令安装: ~~~ got go-xorm/cmd/xorm ~~~ 或者你可以从 [gobuild](http://gobuild.io/download/github.com/lunny/got) 下载后解压到可执行路径。 ### 源码安装 `go get github.com/go-xorm/cmd/xorm` 同时你需要安装如下依赖: - github.com/go-xorm/xorm - Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) - MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv) - Postgres: [github.com/lib/pq](https://github.com/lib/pq) - SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) ** 对于sqlite3的支持,你需要自己进行编译 `go build -tags sqlite3` 因为sqlite3需要cgo的支持。 ### 命令列表 有如下可用的命令: - **reverse** 反转一个数据库结构,生成代码 - **shell** 通用的数据库操作客户端,可对数据库结构和数据操作 - **dump** Dump数据库中所有结构和数据到标准输出 - **source** 从标注输入中执行SQL文件 - **driver** 列出所有支持的数据库驱动 ### reverse Reverse command is a tool to convert your database struct to all kinds languages of structs or classes. After you installed the tool, you can type `xorm help reverse` to get help example: sqlite:`xorm reverse sqite3 test.db templates/goxorm` mysql:`xorm reverse mysql root:@/xorm_test?charset=utf8 templates/goxorm` mymysql:`xorm reverse mymysql xorm_test2/root/ templates/goxorm` postgres:`xorm reverse postgres "dbname=xorm_test sslmode=disable" templates/goxorm` will generated go files in `./model` directory ### Template and Config Now, xorm tool supports go and c++ two languages and have go, goxorm, c++ three of default templates. In template directory, we can put a config file to control how to generating. ~~~ lang=go genJson=1 ~~~ lang must be go or c++ now.genJson can be 1 or 0, if 1 then the struct will have json tag. ### Shell Shell command provides a tool to operate database. For example, you can create table, alter table, insert data, delete data and etc. `xorm shell sqlite3 test.db` will connect to the sqlite3 database and you can type `help` to list all the shell commands. ### Dump Dump command provides a tool to dump all database structs and data as SQL to your standard output. `xorm dump sqlite3 test.db` could dump sqlite3 database test.db to standard output. If you want to save to file, justtype `xorm dump sqlite3 test.db > test.sql`. ### Source `xorm source sqlite3 test.db < test.sql` will execute sql file on the test.db. ### Driver List all supported drivers since default build will not include sqlite3. ### LICENSE BSD License [http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
';

事件

最后更新于:2022-04-02 01:38:06

### 事件 xorm支持两种方式的事件,一种是在Struct中的特定方法来作为事件的方法,一种是在执行语句的过程中执行事件。 在Struct中作为成员方法的事件如下: - BeforeInsert() - BeforeUpdate() - BeforeDelete() - `func BeforeSet(name string, cell xorm.Cell)` 在 Get 或 Find 方法中,当数据已经从数据库查询出来,而在设置到结构体之前调用。 - AfterInsert() - AfterUpdate() - AfterDelete() 在语句执行过程中的事件方法为: - Before(beforeFunc interface{}) - After(afterFunc interface{}) 其中beforeFunc和afterFunc的原型为func(bean interface{}).
';

缓存

最后更新于:2022-04-02 01:38:04

### 缓存 xorm内置了一致性缓存支持,不过默认并没有开启。要开启缓存,需要在engine创建完后进行配置,如:启用一个全局的内存缓存 ~~~ cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000) engine.SetDefaultCacher(cacher) ~~~ 上述代码采用了LRU算法的一个缓存,缓存方式是存放到内存中,缓存struct的记录数为1000条,缓存针对的范围是所有具有主键的表,没有主键的表中的数据将不会被缓存。如果只想针对部分表,则: ~~~ cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000) engine.MapCacher(&user, cacher) ~~~ 如果要禁用某个表的缓存,则: ~~~ engine.MapCacher(&user, nil) ~~~ 设置完之后,其它代码基本上就不需要改动了,缓存系统已经在后台运行。 当前实现了内存存储的CacheStore接口MemoryStore,如果需要采用其它设备存储,可以实现CacheStore接口。 不过需要特别注意不适用缓存或者需要手动编码的地方: 1. 当使用了`Distinct`,`Having`,`GroupBy`方法将不会使用缓存 1. 在`Get`或者`Find`时使用了`Cols`,`Omit`方法,则在开启缓存后此方法无效,系统仍旧会取出这个表中的所有字段。 1. 在使用Exec方法执行了方法之后,可能会导致缓存与数据库不一致的地方。因此如果启用缓存,尽量避免使用Exec。如果必须使用,则需要在使用了Exec之后调用ClearCache手动做缓存清除的工作。比如: ~~~ engine.Exec("update user set name = ? where id = ?", "xlw", 1) engine.ClearCache(new(User)) ~~~ 缓存的实现原理如下图所示: ![cache design](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-23_55d9d87c254a3.png)
';

事务处理

最后更新于:2022-04-02 01:38:01

### 事务处理 当使用事务处理时,需要创建Session对象。在进行事物处理时,可以混用ORM方法和RAW方法,如下代码所示: ~~~ session := engine.NewSession() defer session.Close() // add Begin() before any action err := session.Begin() user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()} _, err = session.Insert(&user1) if err != nil { session.Rollback() return } user2 := Userinfo{Username: "yyy"} _, err = session.Where("id = ?", 2).Update(&user2) if err != nil { session.Rollback() return } _, err = session.Exec("delete from userinfo where username = ?", user2.Username) if err != nil { session.Rollback() return } // add Commit() after all actions err = session.Commit() if err != nil { return } ~~~ - 注意如果您使用的是mysql,数据库引擎为innodb事务才有效,myisam引擎是不支持事务的。
';

执行SQL命令

最后更新于:2022-04-02 01:37:59

### 执行SQL命令 也可以直接执行一个SQL命令,即执行Insert, Update, Delete 等操作。此时不管数据库是何种类型,都可以使用 ` 和 ? 符号。 ~~~ sql = "update `userinfo` set username=? where id=?" res, err := engine.Exec(sql, "xiaolun", 1) ~~~
';

执行SQL查询

最后更新于:2022-04-02 01:37:57

### 执行SQL查询 也可以直接执行一个SQL查询,即Select命令。在Postgres中支持原始SQL语句中使用 ` 和 ? 符号。 ~~~ sql := "select * from userinfo" results, err := engine.Query(sql) ~~~ 当调用`Query`时,第一个返回值`results`为`[]map[string][]byte`的形式。
';

软删除Deleted

最后更新于:2022-04-02 01:37:55

### 软删除Deleted Deleted可以让您不真正的删除数据,而是标记一个删除时间。使用此特性需要在xorm标记中使用deleted标记,如下所示进行标记,对应的字段必须为time.Time类型。 ~~~ type User struct { Id int64 Name string DeletedAt time.Time `xorm:"deleted"` } ~~~ 在Delete()时,deleted标记的字段将会被自动更新为当前时间而不是去删除该条记录,如下所示: ~~~ var user User engine.Id(1).Get(&user) // SELECT * FROM user WHERE id = ? engine.Id(1).Delete(&user) // UPDATE user SET ..., deleted_at = ? WHERE id = ? engine.Id(1).Get(&user) // 再次调用Get,此时将返回false, nil,即记录不存在 engine.Id(1).Delete(&user) // 再次调用删除会返回0, nil,即记录不存在 ~~~ 那么如果记录已经被标记为删除后,要真正的获得该条记录或者真正的删除该条记录,需要启用Unscoped,如下所示: ~~~ var user User engine.Id(1).Unscoped().Get(&user) // 此时将可以获得记录 engine.Id(1).Unscoped().Delete(&user) // 此时将可以真正的删除记录 ~~~
';

删除数据

最后更新于:2022-04-02 01:37:52

### 删除数据 删除数据`Delete`方法,参数为struct的指针并且成为查询条件。 ~~~ user := new(User) affected, err := engine.Id(id).Delete(user) ~~~ `Delete`的返回值第一个参数为删除的记录数,第二个参数为错误。 注意:当删除时,如果user中包含有bool,float64或者float32类型,有可能会使删除失败。具体请查看 [FAQ](#)
';

更新时间Updated

最后更新于:2022-04-02 01:37:50

### 更新时间Updated Updated可以让您在记录插入或每次记录更新时自动更新数据库中的标记字段为当前时间,需要在xorm标记中使用updated标记,如下所示进行标记,对应的字段必须为time.Time类型。 ~~~ type User struct { Id int64 Name string UpdatedAt time.Time `xorm:"updated"` } ~~~ 在Insert(), InsertOne(), Update()方法被调用时,updated标记的字段将会被自动更新为当前时间,如下所示: ~~~ var user User engine.Id(1).Get(&user) // SELECT * FROM user WHERE id = ? engine.Id(1).Update(&user) // UPDATE user SET ..., updaetd_at = ? WHERE id = ? ~~~
';

乐观锁Version

最后更新于:2022-04-02 01:37:48

### 乐观锁Version 要使用乐观锁,需要使用version标记type User struct { Id int64 Name string Version int `xorm:"version"`} 在Insert时,version标记的字段将会被设置为1,在Update时,Update的内容必须包含version原来的值。 ~~~ var user User engine.Id(1).Get(&user) // SELECT * FROM user WHERE id = ? engine.Id(1).Update(&user) // UPDATE user SET ..., version = version + 1 WHERE id = ? AND version = ? ~~~
';

更新数据

最后更新于:2022-04-02 01:37:45

### 更新数据 更新数据使用`Update`方法,Update方法的第一个参数为需要更新的内容,可以为一个结构体指针或者一个Map[string]interface{}类型。当传入的为结构体指针时,只有非空和0的field才会被作为更新的字段。当传入的为Map类型时,key为数据库Column的名字,value为要更新的内容。 ~~~ user := new(User) user.Name = "myname" affected, err := engine.Id(id).Update(user) ~~~ 这里需要注意,Update会自动从user结构体中提取非0和非nil得值作为需要更新的内容,因此,如果需要更新一个值为0,则此种方法将无法实现,因此有两种选择: - 1.通过添加Cols函数指定需要更新结构体中的哪些值,未指定的将不更新,指定了的即使为0也会更新。 ~~~ affected, err := engine.Id(id).Cols("age").Update(&user) ~~~ - 2.通过传入map[string]interface{}来进行更新,但这时需要额外指定更新到哪个表,因为通过map是无法自动检测更新哪个表的。 ~~~ affected, err := engine.Table(new(User)).Id(id).Update(map[string]interface{}{"age":0}) ~~~
';

Rows方法

最后更新于:2022-04-02 01:37:43

### Rows方法 Rows方法和Iterate方法类似,提供逐条执行查询到的记录的方法,不过Rows更加灵活好用。 ~~~ user := new(User) rows, err := engine.Where("id >?", 1).Rows(user) if err != nil { } defer rows.Close() for rows.Next() { err = rows.Scan(user) //... } ~~~
';

Count方法

最后更新于:2022-04-02 01:37:41

### Count方法 统计数据使用`Count`方法,Count方法的参数为struct的指针并且成为查询条件。 ~~~ user := new(User) total, err := engine.Where("id >?", 1).Count(user) ~~~
';

Iterate方法

最后更新于:2022-04-02 01:37:39

';

Join的使用

最后更新于:2022-04-02 01:37:36

### Join的使用 - Join(string,interface{},string) 第一个参数为连接类型,当前支持INNER, LEFT OUTER, CROSS中的一个值,第二个参数为表名,可以为字符串或者bean,第三个参数为连接条件。 以下将通过示例来讲解具体的用法: 假如我们拥有两个表user和group,每个User只在一个Group中,那么我们可以定义对应的struct ~~~ type Group struct { Id int64 Name string } ~~~ ~~~ type User struct { Id int64 Name string GroupId int64 `xorm:"index"` } ~~~ OK。问题来了,我们现在需要列出所有的User,并且列出对应的GroupName。利用extends和Join我们可以比较优雅的解决这个问题。代码如下: ~~~ type UserGroup struct { User `xorm:"extends"` Name string } func (UserGroup) TableName() string { return "user" } users := make([]UserGroup, 0) engine.Join("INNER", "group", "group.id = user.group_id").Find(&users) ~~~ 这里我们将User这个匿名结构体加了xorm的extends标记(实际上也可以是非匿名的结构体,只要有extends标记即可),这样就减少了重复代码的书写。实际上这里我们直接用Sql函数也是可以的,并不一定非要用Join。 ~~~ users := make([]UserGroup, 0) engine.Sql("select user.*, group.name from user, group where user.group_id = group.id").Find(&users) ~~~ 然后,我们忽然发现,我们还需要显示Group的Id,因为我们需要链接到Group页面。这样又要加一个字段,算了,不如我们把Group也加个extends标记吧,代码如下: ~~~ type UserGroup struct { User `xorm:"extends"` Group `xorm:"extends"` } func (UserGroup) TableName() string { return "user" } users := make([]UserGroup, 0) engine.Join("INNER", "group", "group.id = user.group_id").Find(&users) ~~~ 这次,我们把两个表的所有字段都查询出来了,并且赋值到对应的结构体上了。 这里要注意,User和Group分别有Id和Name,这个是重名的,但是xorm是可以区分开来的,不过需要特别注意UserGroup中User和Group的顺序,如果顺序反了,则有可能会赋值错误,但是程序不会报错。 这里的顺序应遵循如下原则: ~~~ 结构体中extends标记对应的结构顺序应和最终生成SQL中对应的表出现的顺序相同。 ~~~ 还有一点需要注意的,如果在模板中使用这个UserGroup结构体,对于字段名重复的必须加匿名引用,如: 对于不重复字段,可以`{{.GroupId}}`,对于重复字段`{{.User.Id}}`和`{{.Group.Id}}` 这是2个表的用法,3个或更多表用法类似,如: ~~~ type Type struct { Id int64 Name string } type UserGroupType struct { User `xorm:"extends"` Group `xorm:"extends"` Type `xorm:"extends"` } users := make([]UserGroupType, 0) engine.Table("user").Join("INNER", "group", "group.id = user.group_id"). Join("INNER", "type", "type.id = user.type_id"). Find(&users) ~~~ 同时,在使用Join时,也可同时使用Where和Find的第二个参数作为条件,Find的第二个参数同时也允许为各种bean来作为条件。Where里可以是各个表的条件,Find的第二个参数只是被关联表的条件。 ~~~ engine.Table("user").Join("INNER", "group", "group.id = user.group_id"). Join("INNER", "type", "type.id = user.type_id"). Where("user.name like ?", "%"+name+"%").Find(&users, &User{Name:name}) ~~~
';

Find方法

最后更新于:2022-04-02 01:37:34

### Find方法 查询多条数据使用`Find`方法,Find方法的第一个参数为`slice`的指针或`Map`指针,即为查询后返回的结果,第二个参数可选,为查询的条件struct的指针。 1) 传入Slice用于返回数据 ~~~ everyone := make([]Userinfo, 0) err := engine.Find(&everyone) pEveryOne := make([]*Userinfo, 0) err := engine.Find(&pEveryOne) ~~~ 2) 传入Map用户返回数据,map必须为`map[int64]Userinfo`的形式,map的key为id,因此对于复合主键无法使用这种方式。 ~~~ users := make(map[int64]Userinfo) err := engine.Find(&users) pUsers := make(map[int64]*Userinfo) err := engine.Find(&pUsers) ~~~ 3) 也可以加入各种条件 ~~~ users := make([]Userinfo, 0) err := engine.Where("age > ? or name = ?", 30, "xlw").Limit(20, 10).Find(&users) ~~~
';

Get方法

最后更新于:2022-04-02 01:37:32

### Get方法 查询单条数据使用`Get`方法,在调用Get方法时需要传入一个对应结构体的指针,同时结构体中的非空field自动成为查询的条件和前面的方法条件组合在一起查询。 如: 1) 根据Id来获得单条数据: ~~~ user := new(User) has, err := engine.Id(id).Get(user) // 复合主键的获取方法 // has, errr := engine.Id(xorm.PK{1,2}).Get(user) ~~~ 2) 根据Where来获得单条数据: ~~~ user := new(User) has, err := engine.Where("name=?", "xlw").Get(user) ~~~ 3) 根据user结构体中已有的非空数据来获得单条数据: ~~~ user := &User{Id:1} has, err := engine.Get(user) ~~~ 或者其它条件 ~~~ user := &User{Name:"xlw"} has, err := engine.Get(user) ~~~ 返回的结果为两个参数,一个`has`为该条记录是否存在,第二个参数`err`为是否有错误。不管err是否为nil,has都有可能为true或者false。
';