高性能数据库ORM框架 GoMybatis

 

  • 文档

    前言

    学习过原生的Go链接Mysql的方法,使用Go自带的“database/sql”数据库链接api。
    “github.com/go-sql-driver/mysql”mysql驱动,通过比较原生的方法去写sql和处理事务。

    目前开源界也有好多封装好的Orm操作框架:

    Java系(Mybatis,MybatisPlus,hibernate ...)
    Go系 (xorm,gorm,gomybatis ...)
    总所周知,在java/go系orm框架中,国外互联网公司程序员喜欢用hibernate/gorm(这是因为国外产品稳定,需求 清晰,代码素质普遍高),反观国内java系互联网公司则喜欢mybatis之流(需求频繁变动,水平参差不齐,sql优化方便)
  • 我的观点
    JPA/Hibernate.Gorm之流都比较复杂,团队中要有人Hold住它,否则后期及其容易踩坑;
    Mybatis框架直观,但是基本crud功能应该简化一下,毕竟重复度极高(重点:而且简化的同时可以扩展逻辑)

GoMybatis 框架介绍:

GoMybatis是一款总结了以上许多框架的优缺点的ORM框架,并且极力希望在 维护性/可读性/性能/易用性/之上做到均衡(正如go的思想一样,大道至简)
项目地址 https://github.com/zhuxiujia/GoMybatis
GoMybatis并不是一夜之间想出来的,之前阅读过Hibernate、MybatisPlus ,xorm,gorm,gobatis(需要go generate生成中间代码)还有go标准库(database/sql)的部分源码,总结经验而来。

  • GoMybatis 特性介绍: 整体基于标准库“database/sql”开发而来,干净无依赖,结构体+闭包+反射+代理实现 而不是使用go generate生成*.go等中间代码(利用反射函数闭包解决了gobatis框架免去生成代码的缺陷)
    吸收mybatis plus框架乐观锁,逻辑删除功能(当然你也可以手动在sql中加入,就是比较繁琐 好处是可读性高)
    实现了AST抽象语法树,能在#{}表达式中灵活使用公式
    增加了模板标签,减少普通CRUD操作的重复度(mybatis框架是没有的,意味着普通增删改查也得写sql)

  • gomybatis+mysql数据库使用教程:

    使用教程

    教程源码 https://github.com/zhuxiujia/GoMybatis/tree/master/example

设置好GoPath,用go get 命令下载GoMybatis和对应的数据库驱动

go get github.com/zhuxiujia/GoMybatis
go get github.com/go-sql-driver/mysql

实际使用mapper 定义xml内容,建议以*Mapper.xml文件存于项目目录中,在编辑xml时就可享受GoLand等IDE渲染和智能提示。生产环境可以使用statikFS把xml文件打包进程序里

var xmlBytes = []byte(`
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://raw.githubusercontent.com/zhuxiujia/GoMybatis/master/mybatis-3-mapper.dtd">
<mapper>
    <select id="SelectAll">
        select * from biz_activity where delete_flag=1 order by create_time desc
    </select>
</mapper>
`)
import (
    "fmt"
    _ "github.com/go-sql-driver/mysql" //选择需要的数据库驱动导入
    "github.com/zhuxiujia/GoMybatis"
)
type ExampleActivityMapperImpl struct {
     SelectAll  func() ([]Activity, error)
}

func main() {
    var engine = GoMybatis.GoMybatisEngine{}.New()
    //Mysql链接格式 用户名:密码@(数据库链接地址:端口)/数据库名称,如root:123456@(***.com:3306)/test
    err := engine.Open("mysql", "*?charset=utf8&parseTime=True&loc=Local")
    if err != nil {
       panic(err)
    }
    var exampleActivityMapperImpl ExampleActivityMapperImpl

    //加载xml实现逻辑到ExampleActivityMapperImpl
    engine.WriteMapperPtr(&exampleActivityMapperImpl, xmlBytes)

    //使用mapper
    result, err := exampleActivityMapperImpl.SelectAll(&result)
        if err != nil {
       panic(err)
    }
    fmt.Println(result)
}

功能:模板标签CRUD 简化(必须依赖一个resultMap 标签)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://raw.githubusercontent.com/zhuxiujia/GoMybatis/master/mybatis-3-mapper.dtd">
<mapper>
    <!--logic_enable 逻辑删除字段-->
    <!--logic_deleted 逻辑删除已删除字段-->
    <!--logic_undelete 逻辑删除 未删除字段-->
    <!--version_enable 乐观锁版本字段,支持int,int8,int16,int32,int64-->
    <resultMap id="BaseResultMap" tables="biz_activity">
        <id column="id" property="id"/>
        <result column="name" property="name" langType="string"/>
        <result column="pc_link" property="pcLink" langType="string"/>
        <result column="h5_link" property="h5Link" langType="string"/>
        <result column="remark" property="remark" langType="string"/>
        <result column="version" property="version" langType="int"
                version_enable="true"/>
        <result column="create_time" property="createTime" langType="time.Time"/>
        <result column="delete_flag" property="deleteFlag" langType="int"
                logic_enable="true"
                logic_undelete="1"
                logic_deleted="0"/>
    </resultMap>
    <!--模板标签: columns wheres sets 支持逗号,分隔表达式,*?* 为判空表达式-->
    <!--插入模板:默认id="insertTemplete,test="field != null",where自动设置逻辑删除字段,支持批量插入" -->
    <insertTemplete/>
    <!--查询模板:默认id="selectTemplete,where自动设置逻辑删除字段-->
    <selectTemplete wheres="name?name = #{name}"/>
    <!--更新模板:默认id="updateTemplete,set自动设置乐观锁版本号-->
    <updateTemplete sets="name?name = #{name},remark?remark=#{remark}" wheres="id?id = #{id}"/>
    <!--删除模板:默认id="deleteTemplete,where自动设置逻辑删除字段-->
    <deleteTemplete wheres="name?name = #{name}"/>
</mapper>

xml对应以下定义的Mapper结构体方法

type Activity struct {
    Id         string    `json:"id"`
    Uuid       string    `json:"uuid"`
    Name       string    `json:"name"`
    PcLink     string    `json:"pcLink"`
    H5Link     string    `json:"h5Link"`
    Remark     string    `json:"remark"`
    Version    int       `json:"version"`
    CreateTime time.Time `json:"createTime"`
    DeleteFlag int       `json:"deleteFlag"`
}
type ExampleActivityMapper struct {
    SelectTemplete      func(name string) ([]Activity, error) `mapperParams:"name"`
    InsertTemplete      func(arg Activity) (int64, error)
    InsertTempleteBatch func(args []Activity) (int64, error) `mapperParams:"args"`
    UpdateTemplete      func(arg Activity) (int64, error)    `mapperParams:"name"`
    DeleteTemplete      func(name string) (int64, error)     `mapperParams:"name"`
}

功能:动态数据源

        //添加第二个mysql数据库,请把MysqlUri改成你的第二个数据源链接
    GoMybatis.Open("mysql", MysqlUri)
    //动态数据源路由
    var router = GoMybatis.GoMybatisDataSourceRouter{}.New(func(mapperName string) *string {
        //根据包名路由指向数据源
        if strings.Contains(mapperName, "example.") {
            var url = MysqlUri//第二个mysql数据库,请把MysqlUri改成你的第二个数据源链接
            fmt.Println(url)
            return &url
        }
        return nil
    })

功能:自定义日志输出

    engine.SetLogEnable(true)
    engine.SetLog(&GoMybatis.LogStandard{
        PrintlnFunc: func(messages []byte) {
          //do someting save messages
        },
    })

功能:异步日志-基于消息队列日志

Image text

功能:嵌套事务-事务传播行为

事务类型说明
PROPAGATION_REQUIRED 表示如果当前事务存在,则支持当前事务。否则,会启动一个新的事务。默认事务类型。
PROPAGATION_SUPPORTS 表示如果当前事务存在,则支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 表示如果当前事务存在,则支持当前事务,如果当前没有事务,则返回事务嵌套错误。
PROPAGATION_REQUIRES_NEW 表示新建一个全新Session开启一个全新事务,如果当前存在事务,则把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 表示以非事务方式执行操作,如果当前存在事务,则新建一个Session以非事务方式执行操作,把当前事务挂起。
PROPAGATION_NEVER 表示以非事务方式执行操作,如果当前存在事务,则返回事务嵌套错误。
PROPAGATION_NESTED 表示如果当前事务存在,则在嵌套事务内执行,如嵌套事务回滚,则只会在嵌套事务内回滚,不会影响当前事务。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
PROPAGATION_NOT_REQUIRED 表示如果当前没有事务,就新建一个事务,否则返回错误。
 //嵌套事务的服务
type TestService struct {
    exampleActivityMapper *ExampleActivityMapper //服务包含一个mapper操作数据库,类似java spring mvc
    UpdateName   func(id string, name string) error   `tx:"" rollback:"error"`
    UpdateRemark func(id string, remark string) error `tx:"" rollback:"error"`
}
func main()  {
    var testService TestService
    testService = TestService{
        exampleActivityMapper: &exampleActivityMapper,
        UpdateRemark: func(id string, remark string) error {
            testService.exampleActivityMapper.SelectByIds([]string{id})
            panic(errors.New("业务异常")) // panic 触发事务回滚策略
            return nil                   // rollback:"error"指定了返回error类型 且不为nil 就会触发事务回滚策略
        },
        UpdateName: func(id string, name string) error {
            testService.exampleActivityMapper.SelectByIds([]string{id})
            return nil
        },
    }
    GoMybatis.AopProxyService(&testService, &engine)//必须使用AOP代理服务的func
    testService.UpdateRemark("1","remark")
}

功能:内置xml生成工具- 根据用户定义的struct结构体生成对应的 mapper.xml

  //step1 定义你的数据库模型,必须包含 json注解(默认为数据库字段), gm:""注解指定 值是否为 id,version乐观锁,logic逻辑软删除
  type UserAddress struct {
    Id            string `json:"id" gm:"id"`
    UserId        string `json:"user_id"`
    RealName      string `json:"real_name"`
    Phone         string `json:"phone"`
    AddressDetail string `json:"address_detail"`

    Version    int       `json:"version" gm:"version"`
    CreateTime time.Time `json:"create_time"`
    DeleteFlag int       `json:"delete_flag" gm:"logic"`
}
  • 第二步,在你项目main 目录下建立一个 XmlCreateTool.go 内容如下
    func main() {
      var bean = UserAddress{} //此处只是举例,应该替换为你自己的数据库模型
      GoMybatis.OutPutXml(reflect.TypeOf(bean).Name()+"Mapper.xml", GoMybatis.CreateXml("biz_"+GoMybatis.StructToSnakeString(bean), bean))
    }
    
  • 第三步,执行命令,在当前目录下得到 UserAddressMapper.xml文件
    go run XmlCreateTool.go
    
  • 以下是自动生成的xml文件内容
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
          "https://raw.githubusercontent.com/zhuxiujia/GoMybatis/master/mybatis-3-mapper.dtd">
    <mapper>
      <!--logic_enable 逻辑删除字段-->
      <!--logic_deleted 逻辑删除已删除字段-->
      <!--logic_undelete 逻辑删除 未删除字段-->
      <!--version_enable 乐观锁版本字段,支持int,int8,int16,int32,int64-->
      <resultMap id="BaseResultMap" tables="biz_user_address">
      <id column="id" property="id"/>
      <result column="id" property="id" langType="string"   />
      <result column="user_id" property="user_id" langType="string"   />
      <result column="real_name" property="real_name" langType="string"   />
      <result column="phone" property="phone" langType="string"   />
      <result column="address_detail" property="address_detail" langType="string"   />
      <result column="version" property="version" langType="int" version_enable="true"  />
      <result column="create_time" property="create_time" langType="Time"   />
      <result column="delete_flag" property="delete_flag" langType="int"  logic_enable="true" logic_undelete="1" logic_deleted="0" />
      </resultMap>
    </mapper>
    

配套生态(RPC,JSONRPC,Consul)-搭配GoMybatis

配套生态(RPC,JSONRPC,Consul)-搭配GoMybatis

Go ORM Library.Have Powerful Features like transaction nesting, Optimistic Lock,Logical deletion and more. like mybatis for go golang — Read More

Latest commit to the master branch on 6-6-2021
Download as zip
授权协议:
Apache
开发语言:
go 查看源码»
操作系统:
windows,linux
posted @ 2021-07-05 15:28  dreamw  阅读(806)  评论(0编辑  收藏  举报