简介
xorm是一个简单而强大的Go语言ORM库,它可以使数据库操作变得非常简单。这个库是在原来的xorm的基础上定制和增强的版本。它为xorm提供类似ibatis的配置文件和动态SQL支持,并支持ActiveRecord操作。
github地址:https://github.com/armingli/xorm
//安装
go get -u github.com/xormplus/xorm
数据库映射
ORM框架最重要的就是将数据映射到程序中的数据结构。在Go中,结构体是主要的自定义数据结构,它将数据表映射到go结构体中,从而可以在go程序中使用数据库数据。
在大多数ORM框架中,如果数据库表名称与程序中的数据结构名称一致,并且成员变量与数据库表的字段对应,则ORM底层设计可以自动转换,可以直接查询到数据克隆到程序的变量中。 。
但大多数情况下,这些字段并不对应,需要通过一些配置和约定来实现。
type User struct {
Id int
User string
Password string
Role string
}
在go语言中首字母大写表示访问权限,但是这就和数据不一样了,xorm底层使用了core.IMapper
来试下数据库映射。
https://static.kancloud.cn/xormplus/xorm/167084
映射器 | 描述 |
---|---|
core.SnakeMapper | 支持结构体驼峰式命名和表结构下划线命名之间的转换。 |
core.SameMapper | 支持结构体名称与对应的表名称以及结构体字段名称与对应的表字段名称的命名。 |
core.GonicMapper | 与SnakeMapper非常相似,但是对特定单词有更好的支持,比如ID会被翻译成id而不是i_d |
通过引擎设置:
engine.SetMapper(core.SameMapper{
})
Mapper映射是最理想的操作方式,但有些情况不满足需要使用tag标签来定义,还具有以下属性:
-
如果结构体拥有
TableName() string
的成员方法,那么此方法的返回值即是该结构体对应的数据库表名。 -
engine.Table()
方法可以改变struct对应的数据库表的名称 -
通过sturct中field对应的Tag中使用
xorm:"'column_name'"
可以使该field对应的Column名称为指定名称
数据库操作方法
Xorm是一个完整的ORM框架。使用修改后的框架,您几乎可以避免编写SQL语句。不过写惯了SQL,感觉直接写SQL更直观。
插入
insert into <tablename> (cols ...) values (cols...)
engine.Insert(user)
user
是一个数据库表映射的结构体实例,将实例传入构建一条插入语句。user可以是指针和变量类型。
单条数据插入成功后,如果结构体有自增字段(设置为autoincr),那么自增字段会自动分配数据库中的id。这里需要注意的是,如果插入结构中的自增字段已经被赋值,那么该字段将作为非自增字段插入。
批量插入参数是多个结构体实例。
xorm 支持原生 sql 插入:
engine.Exec()
sql ="insert into user(username,password) values (?, ?)"
res, err := engine.Exec(sql, "xiaoxu", "123456")
// ?会被替换为参数
engine.Sql()
sql ="insert into user(username,password) values (?, ?)"
affected, err := engine.Sql(sql, "xiaoxu", "123456").Execute()
stpl配置文件
XML 配置文件类似于 myabtis.xml。
sql := "insert.example.stpl"
paramMap := map[string]interface{
}{
"key": "config_3", "value": "3"}
affected, err := engine.SqlTemplateClient(sql, ¶mMap).Execute()
stpl配置文件在查询部分有详细介绍。
更新
affected, err := engine.Id(id).Update(user)
id指定更新的数据项,update指定更新的数据元素。 User 是一个结构体实例,其中包含更新的数据。是整体更新的。如果没有某些字段,则不会更新,并且类型的默认值也不会更新。
一般情况下,直接以映射的结构体作为更新的对象,而不是像下面这样对某些字段更新。
affected, err := engine.Id(id).Cols("age").Update(&user)
数据库一般是假删除,即有状态字段,删除就不描述了。
寻找
- ORM查询
xorm查询方法为Get()
和Find()
相当于SELECT
的条件关键字。前者用于单挑数据的查询,后者用于多条数据的查询。
//根据id查询
var user User
engine.Id(1).Get(&user)
// SELECT * FROM user Where id = 1
//where条件查询
has, err := engine.Where("name = ?", name).Get(&user)
// SELECT * FROM user WHERE name = ? LIMIT 1
//数据元素查询
engine.Cols("age", "name").Get(&usr)
// SELECT age, name FROM user limit 1
//数据元素条件查询
has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
// SELECT col1, col2, col3 FROM user WHERE id = ?
//查询所有
everyone := make([]Userinfo, 0)
err := engine.Find(&everyone)
//SELECT * FROM user
Get()
和Find()
的区别在于舍去了LIMIT 1
其它都是完全一样的,语法规定了两个方法只在末尾为结构体赋值,且参数都为指针类型。
配置文件实现动态SQL(特色)
对于orm操作数据,以及通过engine.Sql()
和engine.Exec()
原生sql操作数据库,已经满足大部分要求。但是也有特殊情况,如模糊查询,如果没有查询的参数sql就不能生成对应字段。因此需要使用动态sql。
xorm提供SqlMap配置和SqlTemplate函数来支持类似ibatis的SQL操作
Ibatis是MyBatis通过xml配置文件生成和配置sql的解决方案。这种解决方案需要手写sql,这也是小编习惯的方法。
SqlMap
是针对XML文件的sql配置,SqlTemplate
是针对.stpl
模板的配置(支持动态sql)。
数据库驱动工具创建数据库会话:
package main
import (
"fmt"
_ "gorm.io/driver/mysql"
"xorm.io/xorm"
)
func db() *xorm.Engine {
driverName := "mysql"
dataSource := "root:root@/account?charset=utf8"
engine, err := xorm.NewEngine(driverName, dataSource)
if err != nil {
fmt.Println("数据库连接失败", err)
}
return engine
}
func main() {
//数据项插入
user1 := User{
0,
"test3",
"admin1",
"admin",
}
db().Insert(user1)
//元素插入
db().Table("user").Insert(map[string]interface{
}{
"user": "test", //map类型的key为数据字段,value为值
"password": "123",
"role": "admin",
})
//查询
var users []User
err := db().SQL("SELECT * FROM user").Find(&users)
if err != nil {
println(err)
}
fmt.Println(users)
}
使用sql映射需要先注册sql引擎,SqlMap
或者SqlTemplate
。
1、使用RegisterSqlMap()注册SqlMap配置
2、RegisterSqlTemplate()方法注册SSqlTemplate模板配置
3、SqlMap配置文件总根目录和SqlTemplate模板配置文件总根目录可为同一目录
//注册SqlMap配置,xml格式
err := engine.RegisterSqlMap(xorm.Xml("./sql/oracle", ".xml"))
//注册SqlTemplate配置,使用Pongo2模板引擎
err := engine.RegisterSqlTemplate(xorm.Pongo2("./sql/oracle", ".stpl"))
//注册SqlTemplate配置,使用html/template模板引擎
err := engine.RegisterSqlTemplate(xorm.Default("./sql/oracle", ".tpl"))
db.RegisterSqlMap()过程:
配置文件中sql配置会读入内存并缓存
xml配置文件中sql标签的id属性值作为SqlMap的key,如有重名id,则后加载的覆盖之前加载的配置sql条目
xml的占位符会被参数特换,该方式只能基于简单的sql配置,无法实现动态sql。
db.RegisterSqlTemplate()过程
RegisterSqlTemplate()方法按指定目录遍历所配置的目录及其子目录及其子目录下的所有stpl模板文件
stpl模板文件名作为SqlTemplate存储的key,内容会读入内存并缓存
无论哪种方式,sql映射都是基于key-value完成的,所以在程序中加载key框架会自动调用value(sql)。
sqlMap
xormplus引擎加载配置文件的key的方法,执行SqlMap配置文件中的Sql语句,返回的结果类型为[]map[string]interface{}
。由于sqlmap必须具有通用性因此返回的结果只能是前者的类型,需要开发者自行转化为结构体类型。
package main
import (
"fmt"
"github.com/armingli/xorm"
_ "gorm.io/driver/mysql"
)
type User struct {
Id int
User string
Password string
Role string
}
func db() *xorm.Engine {
//配置数据库驱动
driverName := "mysql"
dataSource := "root:root@/account?charset=utf8"
engine, err := xorm.NewEngine(driverName, dataSource)
if err != nil {
fmt.Println("数据库连接失败", err)
}
//注册sqlmap
err = engine.RegisterSqlMap(xorm.Xml("demo/sqlmap", ".xml"))
if err != nil {
fmt.Println("注册sqlmap异常", err)
}
return engine
}
func main() {
queryInterface, err := db().SqlMapClient("selectAllUsers").Query().List()
if err != nil {
println(err)
}
fmt.Println(queryInterface)
}
也可以通过?
占位符传参:
<sqlMap>
<sql id="sql_s_1">
select id,user,password from user where id = ?
</sql>
</sqlMap>
queryInterface, err := db().SqlMapClient("selectById", 1).Query().List()
if err != nil {
println(err)
}
fmt.Println(queryInterface)
sqmap只能配置一些简单的sql语句。事实上,它在功能上并没有太多的扩展。但是sql和程序的分析,降低了程序的耦合度。
SqlTemplate
执行SqlTemplate配置文件中的Sql语句,返回的结果类型为[]map[string]interface{}
package main
import (
"fmt"
"github.com/armingli/xorm"
_ "gorm.io/driver/mysql"
)
type User struct {
Id int
User string
Password string
Role string
}
func db() *xorm.Engine {
//配置数据库驱动
driverName := "mysql"
dataSource := "root:root@/account?charset=utf8"
engine, err := xorm.NewEngine(driverName, dataSource)
if err != nil {
fmt.Println("数据库连接失败", err)
}
//注册sqltemplate
err = engine.RegisterSqlTemplate(xorm.Pongo2("demo/sqltemplate", ".stpl"))
if err != nil {
fmt.Println("注册sqlmap异常", err)
}
//engine.ShowSQL(true)
return engine
}
func main() {
paramMap_5_2 := map[string]interface{
}{
"id": 2}
//paramMap_5_2 := map[string]interface{}{"id": 0, "user": "xiaoxu"}
results, err := db().SqlTemplateClient("sqltemplate.stpl", ¶mMap_5_2).Query().List()
if err != nil {
println(err)
}
fmt.Println(results)
}
使用SqlTemplate分为三个步骤,
-
下载源代码
-
引擎注册sqltemplate
//注册sqltemplate
err = engine.RegisterSqlTemplate(xorm.Pongo2("demo/sqltemplate", ".stpl"))
if err != nil {
fmt.Println("注册sqlmap异常", err)
}
- 传递参数并返回数据
// map[string]interface{}定义传递参数
paramMap := map[string]interface{
}{
"id": 2}
//paramMap:= map[string]interface{}{"id": 0, "user": "xiaoxu"}
//SqlTemplateClient方法加载key,(这里的key就是单个文件)并传入参数
results, err := db().SqlTemplateClient("sqltemplate.stpl", ¶mMap).Query().List()
if err != nil {
println(err)
}
fmt.Println(results)
使用SqlTemplateClient方法时,某些参数未使用。请记住使用相应的类型0值(默认值)。
如果SqlTemplateClient执行的为DML(insert,update,delete)时返回的是影响行数,使用Execute()
方法。
sql_i_3 := "insert.example.stpl"
paramMap_i_t := map[string]interface{
}{
"key": "config_3", "value": "3"}
affected, err := engine.SqlTemplateClient(sql_i_3, ¶mMap_i_t).Execute()
.stpl
是支持pongo2语言的,如下select * from user where { % if id != 0 %} id=?id { % else%} user=?user { % endif %}
id=?id
和user=?user
中?
后面的字段不能去掉,其和程序中map[string]interface{}
参数的字段对应并必须一致,才能自动赋值。否则查询不出数据。
pongo2 语法:https://github.com/flosch/pongo2
gin框架也有模板语法,SqlTemplate也支持使用gin模板语法,所以将sql引擎注册为gin-html/template模板引擎。
//注册SqlTemplate配置,使用html/template模板引擎
err := engine.RegisterSqlTemplate(xorm.Default("./sql/oracle", ".tpl"))
更多步骤:https://www.kancloud.cn/xormplus/xorm/167081
我尝试了一下,没有官网的demo还是搞不懂。希望知道的人留言指导一下。