项目作者: xfali

项目描述 :
golang的ORM框架,类似Java的Mybatis。支持直接执行sql语句以及xml、go template、动态sql。
高级语言: Go
项目地址: git://github.com/xfali/gobatis.git
创建时间: 2019-04-10T12:24:44Z
项目社区:https://github.com/xfali/gobatis

开源协议:Apache License 2.0

关键词:
dynamic-sql golang mybatis orm template

下载


gobatis

license card
go version
Go Report Card
codecov report
workflow
Go Reference
lasted release

介绍

gobatis是一个golang的ORM框架,类似Java的Mybatis。支持直接执行sql语句以及动态sql。

建议配合gobatis-cmd自动代码、sql生成工具使用。

支持的动态sql标签:

标签 说明
if 动态 SQL 通常要做的事情是根据条件包含 where 子句的一部分。
where where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。
set set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号。
include 使用sql标签定义的语句替换。
choose
when
otherwise
有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,gobatis 提供了 choose 元素,它有点像switch 语句。
foreach foreach 允许指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。

除了xml之外,gobatis也支持使用go template的mapper格式。

待完成项

  • 继续完善动态sql支持(trim)
  • 性能优化:增加动态sql缓存
    (已经实现,但测试发现性能提升很小,目前该功能被关闭)

使用

1、配置数据库,获得SessionManager

  1. func InitDB() *gobatis.SessionManager {
  2. fac := gobatis.NewFactory(
  3. gobatis.SetMaxConn(100),
  4. gobatis.SetMaxIdleConn(50),
  5. gobatis.SetDataSource(&datasource.MysqlDataSource{
  6. Host: "localhost",
  7. Port: 3306,
  8. DBName: "test",
  9. Username: "root",
  10. Password: "123",
  11. Charset: "utf8",
  12. }))
  13. return gobatis.NewSessionManager(&fac)
  14. }

注意:

gobatis.NewFactory当连接数据库失败时会返回nil,如果需要知道具体的失败原因请使用:

  1. fac, err := gobatis.CreateFactory(
  2. gobatis.SetMaxConn(100),
  3. gobatis.SetMaxIdleConn(50),
  4. gobatis.SetDataSource(&datasource.MysqlDataSource{
  5. Host: "localhost",
  6. Port: 3306,
  7. DBName: "test",
  8. Username: "root",
  9. Password: "123",
  10. Charset: "utf8",
  11. }))
  12. if err != nil {
  13. t.Log(err)
  14. }

2、定义Model

使用tag(”column”)定义struct,tag指定数据库表中的column name。

  1. type TestTable struct {
  2. //指定table name
  3. TestTable gobatis.TableName "test_table"
  4. //指定表字段id
  5. Id int64 `column:"id"`
  6. //指定表字段username
  7. Username string `column:"username"`
  8. //指定表字段password
  9. Password string `column:"password"`
  10. }

3、注册Model

作用是提高执行速度,已变为非必要步骤,现在gobatis会自动缓存。

  1. func init() {
  2. var model TestTable
  3. gobatis.RegisterModel(&model)
  4. }

4、调用

  1. func Run() {
  2. //初始化db并获得Session Manager
  3. mgr := InitDB()
  4. //获得session
  5. session := mgr.NewSession()
  6. ret := TestTable{}
  7. //使用session查询
  8. session.Select("select * from test_table where id = ${0}").Param(100).Result(&ret)
  9. fmt.printf("%v\n", ret)
  10. }

5、解析说明

5.1、内置动态解析

内置动态解析是gobatis类Mybatis的解析方案(目前是xml mapper文件和直接执行sql的默认解析方式):

  1. ${}表示直接替换,#{}防止sql注入
  2. 与Mybatis类似,语句中${0}、${1}、${2}…${n} 对应的是Param方法中对应的不定参数,最终替换和调用底层Driver
  3. Param方法接受简单类型的不定参数(string、int、time、float等)、struct、map,底层自动解析获得参数,用法为:
  1. param := TestTable{Username:"test_user"}
  2. ret := TestTable{}
  3. session.Select("select * from test_table where username = #{TestTable.username}").Param(param).Result(&ret)
  1. Param解析的参数规则(请务必按此规则对应SQL语句的占位参数):
  • 简单类型

    对应sql参数中的#{0}、#{1}…

  • map类型

    对应sql参数中的#{key1}、#{key2}…

  • struct类型

    对应sql参数中的#{StructName.Field1}、#{StructName.Field2}…

5.2、go template解析

使用go template解析,遵循template解析规则,是template mapper文件的解析方式。

如要要修改直接执行sql的默认解析方式,可通过:

  1. sessionManager.SetParserFactory(gobatis.TemplateParserFactory)

或者

  1. session.SetParserFactory(gobatis.TemplateParserFactory)

调用后可使用template的方式直接解析执行sql:

  1. session.Select("SELECT * FROM test_table WHERE id = {{.}}").Param(2).Result(&ret)

gobatis内置where、set、arg自定义函数,用于智能生成动态sql

arg用于将对象动态转换为占位符,并保存为sql参数,如:

  1. SELECT * FROM TABLE_NAME WHERE name = {{arg .Name}}

以mysql为例,将解析为:

  1. SELECT * FROM TABLE_NAME WHERE name = ?

同时Name的值将自动保存为SQL参数,自动传入,起到类似内置动态解析中#{MODEL.Name}的效果。

6、事务

使用

  1. mgr.NewSession().Tx(func(session *gobatis.Session) error {
  2. ret := 0
  3. session.Insert("insert_id").Param(testV).Result(&ret)
  4. t.Logf("ret %d\n", ret)
  5. session.Select("select_id").Param().Result(&testList)
  6. for _, v := range testList {
  7. t.Logf("data: %v", v)
  8. }
  9. //commit
  10. return nil
  11. })
  1. 当参数的func返回nil,则提交
  2. 当参数的func返回非nil的错误,则回滚
  3. 当参数的func内抛出panic,则回滚

7、扫描mapper文件

  1. err := gobatis.ScanMapperFile(${MAPPER_FILE_DIR})
  2. if err != nil {
  3. t.Fatal(err)
  4. }

8、xml

gobatis支持xml的sql解析及动态sql

  1. 直接注册xml
  1. gobatis.RegisterMapperData([]byte(main_xml))

  1. gobatis.RegisterMapperFile(filePath)
  1. xml示例
  1. <mapper namespace="test">
  2. <sql id="columns_id">id,username,password,createtime</sql>
  3. <select id="selectTestTable">
  4. SELECT <include refid="columns_id"> </include> FROM test_table
  5. <where>
  6. <if test="{TestTable.id} != nil and {TestTable.id} != 0">AND id = #{TestTable.id} </if>
  7. <if test="{TestTable.username} != nil">AND username = #{TestTable.username} </if>
  8. <if test="{TestTable.password} != nil">AND password = #{TestTable.password} </if>
  9. <if test="{TestTable.createtime} != nil">AND createtime = #{TestTable.createtime} </if>
  10. </where>
  11. </select>
  12. <select id="selectTestTableCount">
  13. SELECT COUNT(*) FROM test_table
  14. <where>
  15. <if test="{TestTable.id} != nil and {TestTable.id} != 0">AND id = #{TestTable.id} </if>
  16. <if test="{TestTable.username} != nil">AND username = #{TestTable.username} </if>
  17. <if test="{TestTable.password} != nil">AND password = #{TestTable.password} </if>
  18. <if test="{TestTable.createtime} != nil">AND createtime = #{TestTable.createtime} </if>
  19. </where>
  20. </select>
  21. <insert id="insertTestTable">
  22. INSERT INTO test_table (id,username,password,createtime)
  23. VALUES(
  24. #{TestTable.id},
  25. #{TestTable.username},
  26. #{TestTable.password},
  27. #{TestTable.createtime}
  28. )
  29. </insert>
  30. <insert id="insertBatchTestTable">
  31. INSERT INTO test_table (id,username,password,createtime)
  32. VALUES
  33. <foreach item="item" index="index" collection="{0}" open="" separator="," close="">
  34. (#{item.TestTable.id},#{item.TestTable.username},#{item.TestTable.password},#{item.TestTable.createtime})
  35. </foreach>
  36. </insert>
  37. <update id="updateTestTable">
  38. UPDATE test_table
  39. <set>
  40. <if test="{TestTable.username} != nil"> username = #{TestTable.username} </if>
  41. <if test="{TestTable.password} != nil"> password = #{TestTable.password} </if>
  42. <if test="{TestTable.createtime} != nil"> createtime = #{TestTable.createtime} </if>
  43. </set>
  44. WHERE id = #{TestTable.id}
  45. </update>
  46. <delete id="deleteTestTable">
  47. DELETE FROM test_table
  48. <where>
  49. <if test="{TestTable.id} != nil and {TestTable.id} != 0">AND id = #{TestTable.id} </if>
  50. <if test="{TestTable.username} != nil">AND username = #{TestTable.username} </if>
  51. <if test="{TestTable.password} != nil">AND password = #{TestTable.password} </if>
  52. <if test="{TestTable.createtime} != nil">AND createtime = #{TestTable.createtime} </if>
  53. </where>
  54. </delete>
  55. </mapper>
  1. namespace

xml数据或文件注册之后,session参数sqlid与xml action对应关系为:${NAMESPACE}+”.”+${ACTION_ID}

以2中的xml为例,调用select的方式为:

  1. sess.Select("test.selectTestTable").Param(model).Result(&dataList)

9、template

gobatis也支持go template的sql解析及动态sql

  1. 直接注册template
  1. gobatis.RegisterTemplateData([]byte(main_xml))

  1. gobatis.RegisterTemplateFile(filePath)
  1. template示例
  1. {{define "namespace"}}test{{end}}
  2. {{define "selectTestTable"}}
  3. SELECT id,username,password,createtime FROM test_table
  4. {{where .Id "AND" "id = " (arg .Id) "" | where .Username "AND" "username = " (arg .Username) | where .Password "AND" "password = " (arg .Password) | where .Createtime "AND" "createtime = " (arg .Createtime)}}
  5. {{end}}
  6. {{define "selectTestTableCount"}}
  7. SELECT COUNT(*) FROM test_table
  8. {{where .Id "AND" "id = " (arg .Id) "" | where .Username "AND" "username = " (arg .Username) | where .Password "AND" "password = " (arg .Password) | where .Createtime "AND" "createtime = " (arg .Createtime)}}
  9. {{end}}
  10. {{define "insertTestTable"}}
  11. INSERT INTO test_table(id,username,password,createtime)
  12. VALUES(
  13. {{arg .Id}}, {{arg .Username}}, {{arg .Password}}, {{arg .Createtime}})
  14. {{end}}
  15. {{define "insertBatchTestTable"}}
  16. {{$size := len . | add -1}}
  17. INSERT INTO test_table(id,username,password,createtime)
  18. VALUES {{range $i, $v := .}}
  19. ({{arg $v.Id}}, {{arg $v.Username}}, {{arg $v.Password}}, {{arg $v.Createtime}}){{if lt $i $size}},{{end}}
  20. {{end}}
  21. {{end}}
  22. {{define "updateTestTable"}}
  23. UPDATE test_table
  24. {{set .Id "id = " (arg .Id) "" | set .Username "username = " (arg .Username) | set .Password "password = " (arg .Password) | set .Createtime "createtime = " (arg .Createtime)}}
  25. {{where .Id "AND" "id = " (arg .Id) ""}}
  26. {{end}}
  27. {{define "deleteTestTable"}}
  28. DELETE FROM test_table
  29. {{where .Id "AND" "id = " (arg .Id) "" | where .Username "AND" "username = " (arg .Username) | where .Password "AND" "password = " (arg .Password) | where .Createtime "AND" "createtime = " (arg .Createtime)}}
  30. {{end}}
  1. namespace

template数据或文件可定义一个名称为namespace的子模版,用以定义namespace。

template数据或文件注册之后,session参数sql id与模板对应关系为:${NAMESPACE}+”.”+${ACTION_ID}

以2中的template为例,调用select的方式为:

  1. sess.Select("test.selectTestTable").Param(model).Result(&dataList)

10、gobatis-cmd生成文件使用示例

参考cmd_test

11、 SQL语句构建器

gobatis xml特性有非常强大的动态SQL生成方案,当需要在代码中嵌入SQL语句时,也可使用SQL语句构建器:

  1. import "github.com/xfali/gobatis/builder"
  1. str := builder.Select("A.test1", "B.test2").
  2. Select("B.test3").
  3. From("test_a AS A").
  4. From("test_b AS B").
  5. Where("id = 1").
  6. And().
  7. Where("name=2").
  8. GroupBy("name").
  9. OrderBy("name").
  10. Desc().
  11. Limit(5, 10).
  12. String()
  13. t.Log(str)

其他

1、分页

使用pagehelper: gobatis的配套分页工具

  1. go get github.com/xfali/pagehelper

2、大于/小于转义

使用xml mapper文件会出现大于号“ > ”、小于号“ < ”号解析的问题,gobatis使用CDATA规避此问题。

  1. <![CDATA[ > ]]>
  2. <![CDATA[ < ]]>

3、模糊查询支持

使用LIKE CONCAT(‘%’,#{field},’%’)

举例:

  1. SELECT <include refid="columns_id"> </include> FROM `TEST_TABLE`
  2. <where>
  3. <if test="{TestTable.username} != nil">AND `username` LIKE CONCAT('%',#{TestTable.username},'%') </if>
  4. </where>