简介
xorm是一个简单而强大的Go语言ORM库,通过它可以使数据库操作非常简便。本库是基于原版xorm的定制增强版本,为xorm提供类似ibatis的配置文件及动态SQL支持,支持AcitveRecord操作。
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
mapper | 描述 |
---|---|
core.SnakeMapper | 支持struct为驼峰式命名,表结构为下划线命名之间的转换 |
core.SameMapper | 支持结构体名称和对应的表名称以及结构体field名称与对应的表字段名称相同的命名 |
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配置文件
类似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配置文件来生成和1配置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
尝试了一下,没有官网的演示还是找不到头脑,希望会的大佬留言指导。