docs improved
This commit is contained in:
parent
d1a0338322
commit
44a82b03be
|
@ -0,0 +1 @@
|
|||
go test -v -bench=. -run=XXX
|
|
@ -3,10 +3,11 @@ xorm 快速入门
|
|||
|
||||
* [1.创建Orm引擎](#10)
|
||||
* [2.定义表结构体](#20)
|
||||
* [2.1.名称映射规则](#21)
|
||||
* [2.2.使用Table和Tag改变名称映射](#22)
|
||||
* [2.3.Column属性定义](#23)
|
||||
* [2.4.Go与字段类型对应表](#24)
|
||||
* [2.1.名称映射规则](#21)
|
||||
* [2.2.前缀映射规则和后缀映射规则](#22)
|
||||
* [2.3.使用Table和Tag改变名称映射](#23)
|
||||
* [2.4.Column属性定义](#24)
|
||||
* [2.5.Go与字段类型对应表](#25)
|
||||
* [3.表结构操作](#30)
|
||||
* [3.1 获取数据库信息](#31)
|
||||
* [3.2 表操作](#32)
|
||||
|
@ -19,7 +20,8 @@ xorm 快速入门
|
|||
* [5.3.Get方法](#63)
|
||||
* [5.4.Find方法](#64)
|
||||
* [5.5.Iterate方法](#65)
|
||||
* [5.6.Count方法](#66)
|
||||
* [5.6.Count方法](#66)
|
||||
* [5.7.Rows方法](#67)
|
||||
* [6.更新数据](#70)
|
||||
* [6.1.乐观锁](#71)
|
||||
* [7.删除数据](#80)
|
||||
|
@ -69,13 +71,15 @@ xorm当前支持四种驱动如下:
|
|||
|
||||
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
|
||||
|
||||
* Postgres: [github.com/lib/pq](https://github.com/lib/pq)
|
||||
* Postgres: [github.com/lib/pq](https://github.com/lib/pq)
|
||||
|
||||
* MsSql: [github.com/lunny/godbc](https://githubcom/lunny/godbc)
|
||||
|
||||
NewEngine传入的参数和`sql.Open`传入的参数完全相同,因此,使用哪个驱动前,请查看此驱动中关于传入参数的说明文档。
|
||||
|
||||
在engine创建完成后可以进行一些设置,如:
|
||||
|
||||
1.设置
|
||||
1.错误显示设置,默认如下均为`false`
|
||||
|
||||
* `engine.ShowSQL = true`,则会在控制台打印出生成的SQL语句;
|
||||
* `engine.ShowDebug = true`,则会在控制台打印调试信息;
|
||||
|
@ -93,7 +97,7 @@ f, err := os.Create("sql.log")
|
|||
engine.Logger = f
|
||||
```
|
||||
|
||||
3.engine内部支持连接池接口,默认使用的Go所实现的连接池,同时自带了另外两种实现:一种是不使用连接池,另一种为一个自实现的连接池。推荐使用Go所实现的连接池。如果要使用自己实现的连接池,可以实现`xorm.IConnectPool`并通过`engine.SetPool`进行设置。
|
||||
3.engine内部支持连接池接口,默认使用的Go所实现的连接池,同时自带了另外两种实现:一种是不使用连接池,另一种为一个自实现的连接池。推荐使用Go所实现的连接池。如果要使用自己实现的连接池,可以实现`xorm.IConnectPool`并通过`engine.SetPool`进行设置。推荐使用Go默认的连接池。
|
||||
|
||||
* 如果需要设置连接池的空闲数大小,可以使用`engine.SetIdleConns()`来实现。
|
||||
* 如果需要设置最大打开连接数,则可以使用`engine.SetMaxConns()`来实现。
|
||||
|
@ -111,20 +115,33 @@ xorm支持将一个struct映射为数据库中对应的一张表。映射规则
|
|||
当前SnakeMapper为默认值,如果需要改变时,在engine创建完成后使用
|
||||
|
||||
```Go
|
||||
engine.Mapper = SameMapper{}
|
||||
engine.SetMapper(SameMapper{})
|
||||
```
|
||||
|
||||
当然,如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。
|
||||
同时需要注意的是:
|
||||
|
||||
* 如果你使用了别的命名规则映射方案,也可以自己实现一个IMapper。
|
||||
* 表名称和字段名称的映射规则默认是相同的,当然也可以设置为不同,如:
|
||||
```Go
|
||||
engine.SetTableMapper(SameMapper{})
|
||||
engine.SetColumnMapper(SnakeMapper{})
|
||||
```
|
||||
|
||||
<a name="22" id="22"></a>
|
||||
### 2.2.使用Table和Tag改变名称映射
|
||||
### 2.2.前缀映射规则和后缀映射规则
|
||||
|
||||
* 通过`engine.NewPrefixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的前缀;
|
||||
* 通过`engine.NewSufffixMapper(SnakeMapper{}, "prefix")`可以在SnakeMapper的基础上在命名中添加统一的后缀。
|
||||
|
||||
<a name="23" id="23"></a>
|
||||
### 2.3.使用Table和Tag改变名称映射
|
||||
|
||||
如果所有的命名都是按照IMapper的映射来操作的,那当然是最理想的。但是如果碰到某个表名或者某个字段名跟映射规则不匹配时,我们就需要别的机制来改变。
|
||||
|
||||
通过`engine.Table()`方法可以改变struct对应的数据库表的名称,通过sturct中field对应的Tag中使用`xorm:"'column_name'"`可以使该field对应的Column名称为指定名称。这里使用两个单引号将Column名称括起来是为了防止名称冲突,因为我们在Tag中还可以对这个Column进行更多的定义。如果名称不冲突的情况,单引号也可以不使用。
|
||||
|
||||
<a name="23" id="23"></a>
|
||||
### 2.3.Column属性定义
|
||||
### 2.4.Column属性定义
|
||||
我们在field对应的Tag中对Column的一些属性进行定义,定义的方法基本和我们写SQL定义表结构类似,比如:
|
||||
|
||||
```
|
||||
|
@ -140,10 +157,10 @@ type User struct {
|
|||
|
||||
<table>
|
||||
<tr>
|
||||
<td>name</td><td>当前field对应的字段的名称,可选,如不写,则自动根据field名字和转换规则命名</td>
|
||||
<td>name</td><td>当前field对应的字段的名称,可选,如不写,则自动根据field名字和转换规则命名,如与其它关键字冲突,请使用单引号括起来。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>pk</td><td>是否是Primary Key,如果在一个struct中有两个字段都使用了此标记,则这两个字段构成了复合主键</td>
|
||||
<td>pk</td><td>是否是Primary Key,如果在一个struct中有两个字段都使用了此标记,则这两个字段构成了复合主键,单主键当前支持int32,int,int64,uint32,uint,uint64,string这7中Go的数据类型。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>当前支持30多种字段类型,详情参见 [字段类型](https://github.com/lunny/xorm/blob/master/docs/COLUMNTYPE.md)</td><td>字段类型</td>
|
||||
|
@ -152,7 +169,7 @@ type User struct {
|
|||
<td>autoincr</td><td>是否是自增</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[not ]null</td><td>是否可以为空</td>
|
||||
<td>[not ]null 或 notnull</td><td>是否可以为空</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>unique或unique(uniquename)</td><td>是否是唯一,如不加括号则该字段不允许重复;如加上括号,则括号中为联合唯一索引的名字,此时如果有另外一个或多个字段和本unique的uniquename相同,则这些uniquename相同的字段组成联合唯一索引</td>
|
||||
|
@ -188,11 +205,11 @@ type User struct {
|
|||
|
||||
另外有如下几条自动映射的规则:
|
||||
|
||||
- 1.如果field名称为`Id`而且类型为`int64`的话,会被xorm视为主键,并且拥有自增属性。如果想用`Id`以外的名字做为主键名,可以在对应的Tag上加上`xorm:"pk"`来定义主键。
|
||||
- 1.如果field名称为`Id`而且类型为`int64`的话,会被xorm视为主键,并且拥有自增属性。如果想用`Id`以外的名字或非int64类型做为主键名,必须在对应的Tag上加上`xorm:"pk"`来定义主键,加上`xorm:"autoincr"`作为自增。这里需要注意的是,有些数据库并不允许非主键的自增属性。
|
||||
|
||||
- 2.string类型默认映射为varchar(255),如果需要不同的定义,可以在tag中自定义
|
||||
|
||||
- 3.支持`type MyString string`等自定义的field,支持Slice, Map等field成员,这些成员默认存储为Text类型,并且默认将使用Json格式来序列化和反序列化。也支持数据库字段类型为Blob类型,如果是Blob类型,则先使用Json格式序列化再转成[]byte格式。当然[]byte或者[]uint8默认为Blob类型并且都以二进制方式存储。
|
||||
- 3.支持`type MyString string`等自定义的field,支持Slice, Map等field成员,这些成员默认存储为Text类型,并且默认将使用Json格式来序列化和反序列化。也支持数据库字段类型为Blob类型,如果是Blob类型,则先使用Json格式序列化再转成[]byte格式。当然[]byte或者[]uint8默认为Blob类型并且都以二进制方式存储。具体参见 [go类型<->数据库类型对应表](https://github.com/lunny/xorm/blob/master/docs/AutoMap.md)
|
||||
|
||||
- 4.实现了Conversion接口的类型或者结构体,将根据接口的转换方式在类型和数据库记录之间进行相互转换。
|
||||
```Go
|
||||
|
@ -218,7 +235,7 @@ xorm提供了一些动态获取和修改表结构的方法。对于一般的应
|
|||
## 3.1 获取数据库信息
|
||||
|
||||
* DBMetas()
|
||||
xorm支持获取表结构信息,通过调用`engine.DBMetas()`可以获取到所有的表的信息
|
||||
xorm支持获取表结构信息,通过调用`engine.DBMetas()`可以获取到所有的表,字段,索引的信息。
|
||||
|
||||
<a name="31" id="31"></a>
|
||||
## 3.2.表操作
|
||||
|
@ -270,7 +287,7 @@ user.Name = "myname"
|
|||
affected, err := engine.Insert(user)
|
||||
```
|
||||
|
||||
在插入成功后,如果该结构体有PK字段,则PK字段会被自动赋值为数据库中的id
|
||||
在插入单条数据成功后,如果该结构体有自增字段,则自增字段会被自动赋值为数据库中的id
|
||||
```Go
|
||||
fmt.Println(user.Id)
|
||||
```
|
||||
|
@ -321,22 +338,24 @@ questions[0].Content = "whywhywhwy?"
|
|||
affected, err := engine.Insert(user, &questions)
|
||||
```
|
||||
|
||||
注意:这里虽然支持同时插入,但这些插入并没有事务关系。因此有可能在中间插入出错后,后面的插入将不会继续。
|
||||
这里需要注意以下几点:
|
||||
* 这里虽然支持同时插入,但这些插入并没有事务关系。因此有可能在中间插入出错后,后面的插入将不会继续。
|
||||
* 多条插入会自动生成`Insert into table values (),(),()`的语句,因此这样的语句有一个最大的记录数,根据经验测算在150条左右。大于150条后,生成的sql语句将太长可能导致执行失败。因此在插入大量数据时,目前需要自行分割成每150条插入一次。
|
||||
|
||||
<a name="60" id="60"></a>
|
||||
## 5.查询和统计数据
|
||||
|
||||
所有的查询条件不区分调用顺序,但必须在调用Get,Find,Count这三个函数之前调用。同时需要注意的一点是,在调用的参数中,所有的字符字段名均为映射后的数据库的字段名,而不是field的名字。
|
||||
所有的查询条件不区分调用顺序,但必须在调用Get,Find,Count, Iterate, Rows这几个函数之前调用。同时需要注意的一点是,在调用的参数中,如果采用默认的`SnakeMapper`所有的字符字段名均为映射后的数据库的字段名,而不是field的名字。
|
||||
|
||||
<a name="61" id="61"></a>
|
||||
### 5.1.查询条件方法
|
||||
|
||||
查询和统计主要使用`Get`, `Find`, `Count`三个方法。在进行查询时可以使用多个方法来形成查询条件,条件函数如下:
|
||||
查询和统计主要使用`Get`, `Find`, `Count`, `Rows`, `Iterate`这几个方法。在进行查询时可以使用多个方法来形成查询条件,条件函数如下:
|
||||
|
||||
* Id(interface{})
|
||||
传入一个PK字段的值,作为查询条件,如果是复合主键,则
|
||||
`Id(xorm.PK{1, 2})`
|
||||
传入的两个参数按照struct中定义的顺序赋值。
|
||||
传入的两个参数按照struct中字段出现的顺序赋值。
|
||||
|
||||
* Where(string, …interface{})
|
||||
和Where语句中的条件基本相同,作为条件
|
||||
|
@ -501,6 +520,22 @@ user := new(User)
|
|||
total, err := engine.Where("id >?", 1).Count(user)
|
||||
```
|
||||
|
||||
<a name="67" id="67"></a>
|
||||
### 5.7.Rows方法
|
||||
|
||||
Rows方法和Iterate方法类似,提供逐条执行查询到的记录的方法,不过Rows更加灵活好用。
|
||||
```Go
|
||||
user := new(User)
|
||||
rows, err := engine.Where("id >?", 1).Rows(user)
|
||||
if err != nil {
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
err = rows.Scan(user)
|
||||
//...
|
||||
}
|
||||
```
|
||||
|
||||
<a name="70" id="70"></a>
|
||||
## 6.更新数据
|
||||
|
||||
|
@ -561,29 +596,33 @@ affected, err := engine.Id(id).Delete(user)
|
|||
## 8.执行SQL查询
|
||||
|
||||
也可以直接执行一个SQL查询,即Select命令。在Postgres中支持原始SQL语句中使用 ` 和 ? 符号。
|
||||
|
||||
```Go
|
||||
sql := "select * from userinfo"
|
||||
results, err := engine.Query(sql)
|
||||
```
|
||||
|
||||
当调用`Query`时,第一个返回值`results`为`[]map[string][]byte`的形式。
|
||||
|
||||
<a name="100" id="100"></a>
|
||||
## 9.执行SQL命令
|
||||
|
||||
也可以直接执行一个SQL命令,即执行Insert, Update, Delete 等操作。同样在Postgres中支持原始SQL语句中使用 ` 和 ? 符号。
|
||||
也可以直接执行一个SQL命令,即执行Insert, Update, Delete 等操作。此时不管数据库是何种类型,都可以使用 ` 和 ? 符号。
|
||||
|
||||
```Go
|
||||
sql = "update userinfo set username=? where id=?"
|
||||
sql = "update `userinfo` set username=? where id=?"
|
||||
res, err := engine.Exec(sql, "xiaolun", 1)
|
||||
```
|
||||
|
||||
<a name="110" id="110"></a>
|
||||
## 10.事务处理
|
||||
当使用事务处理时,需要创建Session对象。
|
||||
当使用事务处理时,需要创建Session对象。在进行事物处理时,可以混用ORM方法和RAW方法,如下代码所示:
|
||||
|
||||
```Go
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
// add Begin() before any action
|
||||
err := session.Begin()
|
||||
err := session.Begin()
|
||||
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
|
||||
_, err = session.Insert(&user1)
|
||||
if err != nil {
|
||||
|
@ -638,16 +677,16 @@ engine.MapCacher(&user, nil)
|
|||
|
||||
不过需要特别注意不适用缓存或者需要手动编码的地方:
|
||||
|
||||
1. 在Get或者Find时使用了Cols方法,在开启缓存后此方法无效,系统仍旧会取出这个表中的所有字段。
|
||||
1. 当使用了`Distinct`,`Having`,`GroupBy`方法将不会使用缓存
|
||||
|
||||
2. 在使用Exec方法执行了方法之后,可能会导致缓存与数据库不一致的地方。因此如果启用缓存,尽量避免使用Exec。如果必须使用,则需要在使用了Exec之后调用ClearCache手动做缓存清除的工作。比如:
|
||||
2. 在`Get`或者`Find`时使用了`Cols`,`Omit`方法,则在开启缓存后此方法无效,系统仍旧会取出这个表中的所有字段。
|
||||
|
||||
3. 在使用Exec方法执行了方法之后,可能会导致缓存与数据库不一致的地方。因此如果启用缓存,尽量避免使用Exec。如果必须使用,则需要在使用了Exec之后调用ClearCache手动做缓存清除的工作。比如:
|
||||
```Go
|
||||
engine.Exec("update user set name = ? where id = ?", "xlw", 1)
|
||||
engine.ClearCache(new(User))
|
||||
```
|
||||
|
||||
ClearCacheBean
|
||||
|
||||
缓存的实现原理如下图所示:
|
||||
|
||||

|
||||
|
|
Loading…
Reference in New Issue