zorm 正在参加 2020 年度 OSC 中国开源项目评选,请投票支持!
zorm 在 2020 年度 OSC 中国开源项目评选 中已获得 {{ projectVoteCount }} 票,请投票支持!
投票让它出道
已投票
zorm 获得 2020 年度 OSC 中国开源项目评选「最佳人气项目」 !
zorm 获得 2020 年度 OSC 中国开源项目评选「最佳人气项目」「最积极运营项目」 !
zorm 获得 2020 年度 OSC 中国开源项目评选「最积极运营项目」 !
授权协议 Apache
开发语言 Google Go
操作系统 跨平台
软件类型 开源软件
开源组织
地区 国产
投 递 者 光石头
适用人群 未知
收录时间 2020-03-09

软件简介

Golang 轻量级 ORM,零依赖,支持达梦(dm)、金仓(kingbase) 、神通(shentong) 、南大通用(gbase)mysqlpostgresqloraclemssqlsqlite 数据库 。

  • 基于原生sql语句编写,是springrain的精简和优化.
  • 自带代码生成器
  • 代码精简,主体2500行,零依赖4200行,注释详细,方便定制修改.
  • 支持事务传播,这是zorm诞生的主要原因
  • 支持mysql,postgresql,oracle,mssql,sqlite,dm(达梦),kingbase(人大金仓),shentong(神州通用) ,gbase(南通)
  • 支持多库和读写分离
  • 更新性能zorm,gorm,xorm相当. 读取性能zorm比gorm,xorm快一倍
    go get gitee.com/chunanyong/zorm 
    

    生产使用参考 UserStructService.go

支持国产数据库

达梦(dm)

配置zorm.DataSourceConfig的 DriverName:dm ,DBType:dm
达梦数据库驱动: https://gitee.com/chunanyong/dm
达梦的text类型会映射为dm.DmClob,string不能接收,需要实现zorm.CustomDriverValueConver接口,自定义扩展处理

人大金仓(kingbase)

配置zorm.DataSourceConfig的 DriverName:kingbase ,DBType:kingbase
金仓驱动说明: https://help.kingbase.com.cn/doc-view-8108.html
金仓kingbase 8核心是基于postgresql 9.6,可以使用 https://github.com/lib/pq 进行测试,生产环境建议使用官方驱动.
注意修改 data/kingbase.conf中 ora_input_emptystr_isnull = false,因为golang没有null值,一般数据库都是not null,golang的string默认是'',如果这个设置为true,数据库就会把值设置为null,和字段属性not null 冲突,因此报错.

神州通用(shentong)

建议使用官方驱动,配置zorm.DataSourceConfig的 DriverName:aci ,DBType:shentong

南大通用(gbase)

暂时还未找到官方golang驱动,配置zorm.DataSourceConfig的 DriverName:gbase ,DBType:gbase
暂时先使用odbc驱动,DriverName:odbc ,DBType:gbase

测试用例

https://gitee.com/chunanyong/readygo/blob/master/test/testzorm/BaseDao_test.go

// zorm 使用原生的sql语句,没有对sql语法做限制.语句使用Finder作为载体
// 占位符统一使用?,zorm会根据数据库类型,自动替换占位符,例如postgresql数据库把?替换成$1,$2...
// zorm使用 ctx context.Context 参数实现事务传播,ctx从web层传递进来即可,例如gin的c.Request.Context()
// zorm的事务操作需要显示使用zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {})开启

数据库脚本和实体类

https://gitee.com/chunanyong/readygo/blob/master/test/testzorm/demoStruct.go

生成实体类或手动编写,建议使用代码生成器 https://gitee.com/chunanyong/readygo/tree/master/codegenerator


package testzorm

import (
	"time"

	"gitee.com/chunanyong/zorm"
)

//建表语句

/*

DROP TABLE IF EXISTS `t_demo`;
CREATE TABLE `t_demo`  (
  `id` varchar(50)  NOT NULL COMMENT '主键',
  `userName` varchar(30)  NOT NULL COMMENT '姓名',
  `password` varchar(50)  NOT NULL COMMENT '密码',
  `createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
  `active` int  COMMENT '是否有效(0否,1是)',
  PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = utf8mb4  COMMENT = '例子' ;

*/

//demoStructTableName 表名常量,方便直接调用
const demoStructTableName = "t_demo"

// demoStruct 例子
type demoStruct struct {
	//引入默认的struct,隔离IEntityStruct的方法改动
	zorm.EntityStruct

	//Id 主键
	Id string `column:"id"`

	//UserName 姓名
	UserName string `column:"userName"`

	//Password 密码
	Password string `column:"password"`

	//CreateTime <no value>
	CreateTime time.Time `column:"createTime"`

	//Active 是否有效(0否,1是)
	//Active int `column:"active"`

	//------------------数据库字段结束,自定义字段写在下面---------------//
	//如果查询的字段在column tag中没有找到,就会根据名称(不区分大小写)映射到struct的属性上

	//模拟自定义的字段Active
	Active int


}

//GetTableName 获取表名称
func (entity *demoStruct) GetTableName() string {
	return demoStructTableName
}

//GetPKColumnName 获取数据库表的主键字段名称.因为要兼容Map,只能是数据库的字段名称.
func (entity *demoStruct) GetPKColumnName() string {
	return "id"
}

//newDemoStruct 创建一个默认对象
func newDemoStruct() demoStruct {
	demo := demoStruct{
		//如果Id=="",保存时zorm会调用zorm.FuncGenerateStringID(),默认UUID字符串,也可以自己定义实现方式,例如 zorm.FuncGenerateStringID=funcmyId
		Id:         zorm.FuncGenerateStringID(),
		UserName:   "defaultUserName",
		Password:   "defaultPassword",
		Active:     1,
		CreateTime: time.Now(),
	}
	return demo
}

测试用例即文档

// testzorm 使用原生的sql语句,没有对sql语法做限制.语句使用Finder作为载体
// 占位符统一使用?,zorm会根据数据库类型,自动替换占位符,例如postgresql数据库把?替换成$1,$2...
// zorm使用 ctx context.Context 参数实现事务传播,ctx从web层传递进来即可,例如gin的c.Request.Context()
// zorm的事务操作需要显示使用zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {})开启
package testzorm

import (
	"context"
	"fmt"
	"testing"
	"time"

	"gitee.com/chunanyong/zorm"

	//00.引入数据库驱动
	_ "github.com/go-sql-driver/mysql"
)

//dbDao 代表一个数据库,如果有多个数据库,就对应声明多个DBDao
var dbDao *zorm.DBDao

// ctx默认应该有 web层传入,例如gin的c.Request.Context().这里只是模拟
var ctx = context.Background()

//01.初始化DBDao
func init() {

	//自定义zorm日志输出
	//zorm.LogCallDepth = 4 //日志调用的层级
	//zorm.FuncLogError = myFuncLogError //记录异常日志的函数
	//zorm.FuncLogPanic = myFuncLogPanic //记录panic日志,默认使用ZormErrorLog实现
	//zorm.FuncPrintSQL = myFuncPrintSQL //打印sql的函数

	//自定义日志输出格式,把FuncPrintSQL函数重新赋值
	//log.SetFlags(log.LstdFlags)
	//zorm.FuncPrintSQL = zorm.FuncPrintSQL

	//dbDaoConfig 数据库的配置
	dbDaoConfig := zorm.DataSourceConfig{
		//DSN 数据库的连接字符串
		DSN: "root:root@tcp(127.0.0.1:3306)/readygo?charset=utf8&parseTime=true",
		//数据库驱动名称:mysql,postgres,oci8,sqlserver,sqlite3,dm,kingbase,aci 和DBType对应,处理数据库有多个驱动
		DriverName: "mysql",
		//数据库类型(方言判断依据):mysql,postgresql,oracle,mssql,sqlite,dm,kingbase,shentong 和 DriverName 对应,处理数据库有多个驱动
		DBType: "mysql",
		//MaxOpenConns 数据库最大连接数 默认50
		MaxOpenConns: 50,
		//MaxIdleConns 数据库最大空闲连接数 默认50
		MaxIdleConns: 50,
		//ConnMaxLifetimeSecond 连接存活秒时间. 默认600(10分钟)后连接被销毁重建.避免数据库主动断开连接,造成死连接.MySQL默认wait_timeout 28800秒(8小时)
		ConnMaxLifetimeSecond: 600,
		//PrintSQL 打印SQL.会使用FuncPrintSQL记录SQL
		PrintSQL: true,
		//DefaultTxOptions 事务隔离级别的默认配置,默认为nil
		//DefaultTxOptions: nil,
		//DefaultTxOptions: &sql.TxOptions{Isolation: sql.LevelDefault},
	}

	// 根据dbDaoConfig创建dbDao, 一个数据库只执行一次,第一个执行的数据库为 defaultDao,后续zorm.xxx方法,默认使用的就是defaultDao
	dbDao, _ = zorm.NewDBDao(&dbDaoConfig)
}

//TestInsert 02.测试保存Struct对象
func TestInsert(t *testing.T) {

	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault}),如果txOptions为nil,使用全局DefaultTxOptions
	_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		//创建一个demo对象
		demo := newDemoStruct()

		//保存对象,参数是对象指针.如果主键是自增,会赋值到对象的主键属性
		_, err := zorm.Insert(ctx, &demo)

		//如果返回的err不是nil,事务就会回滚
		return nil, err
	})
	//标记测试失败
	if err != nil {
		t.Errorf("错误:%v", err)
	}
}

//TestInsertSlice 03.测试批量保存Struct对象的Slice
//如果是自增主键,无法对Struct对象里的主键属性赋值
func TestInsertSlice(t *testing.T) {

	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault}),如果txOptions为nil,使用全局DefaultTxOptions
	_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {

		//slice存放的类型是zorm.IEntityStruct!!!,golang目前没有泛型,使用IEntityStruct接口,兼容Struct实体类
		demoSlice := make([]zorm.IEntityStruct, 0)

		//创建对象1
		demo1 := newDemoStruct()
		demo1.UserName = "demo1"
		//创建对象2
		demo2 := newDemoStruct()
		demo2.UserName = "demo2"

		demoSlice = append(demoSlice, &demo1, &demo2)

		//批量保存对象,如果主键是自增,无法保存自增的ID到对象里.
		_, err := zorm.InsertSlice(ctx, demoSlice)

		//如果返回的err不是nil,事务就会回滚
		return nil, err
	})
	//标记测试失败
	if err != nil {
		t.Errorf("错误:%v", err)
	}
}

//TestInsertEntityMap 04.测试保存EntityMap对象,用于不方便使用struct的场景,使用Map作为载体
func TestInsertEntityMap(t *testing.T) {

	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault}),如果txOptions为nil,使用全局DefaultTxOptions
	_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		//创建一个EntityMap,需要传入表名
		entityMap := zorm.NewEntityMap(demoStructTableName)
		//设置主键名称
		entityMap.PkColumnName = "id"
		//如果是自增序列,设置序列的值
		//entityMap.PkSequence = "mySequence"

		//Set 设置数据库的字段值
		//如果主键是自增或者序列,不要entityMap.Set主键的值
		entityMap.Set("id", zorm.FuncGenerateStringID())
		entityMap.Set("userName", "entityMap-userName")
		entityMap.Set("password", "entityMap-password")
		entityMap.Set("createTime", time.Now())
		entityMap.Set("active", 1)

		//执行
		_, err := zorm.InsertEntityMap(ctx, entityMap)

		//如果返回的err不是nil,事务就会回滚
		return nil, err
	})
	//标记测试失败
	if err != nil {
		t.Errorf("错误:%v", err)
	}
}

//TestQueryRow 05.测试查询一个struct对象
func TestQueryRow(t *testing.T) {

	//声明一个对象的指针,用于承载返回的数据
	demo := &demoStruct{}

	//构造查询用的finder
	finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
	//finder = zorm.NewSelectFinder(demoStructTableName, "id,userName") // select id,userName from t_demo
	//finder = zorm.NewFinder().Append("SELECT * FROM " + demoStructTableName) // select * from t_demo

	//finder.Append 第一个参数是语句,后面的参数是对应的值,值的顺序要正确.语句统一使用?,zorm会处理数据库的差异
	finder.Append("WHERE id=? and active in(?)", "41b2aa4f-379a-4319-8af9-08472b6e514e", []int{0, 1})

	//执行查询
	has,err := zorm.QueryRow(ctx, finder, demo)

	if err != nil { //标记测试失败
		t.Errorf("错误:%v", err)
	}

	if has { //数据库存在数据
		//打印结果
		fmt.Println(demo)
	}
}

//TestQueryRowMap 06.测试查询map接收结果,用于不太适合struct的场景,比较灵活
func TestQueryRowMap(t *testing.T) {

	//构造查询用的finder
	finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
	//finder.Append 第一个参数是语句,后面的参数是对应的值,值的顺序要正确.语句统一使用?,zorm会处理数据库的差异
	finder.Append("WHERE id=? and active in(?)", "41b2aa4f-379a-4319-8af9-08472b6e514e", []int{0, 1})
	//执行查询
	resultMap, err := zorm.QueryRowMap(ctx, finder)

	if err != nil { //标记测试失败
		t.Errorf("错误:%v", err)
	}
	//打印结果
	fmt.Println(resultMap)
}

//TestQuery 07.测试查询对象列表
func TestQuery(t *testing.T) {
	//创建用于接收结果的slice
	list := make([]*demoStruct, 0)

	//构造查询用的finder
	finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
	//创建分页对象,查询完成后,page对象可以直接给前端分页组件使用
	page := zorm.NewPage()
	page.PageNo = 1    //查询第1页,默认是1
	page.PageSize = 20 //每页20条,默认是20

	//执行查询.如果不想分页,查询所有数据,page传入nil
	err := zorm.Query(ctx, finder, &list, page)
	if err != nil { //标记测试失败
		t.Errorf("错误:%v", err)
	}
	//打印结果
	fmt.Println("总条数:", page.TotalCount, "  列表:", list)
}

//TestQueryMap 08.测试查询map列表,用于不方便使用struct的场景,一条记录是一个map对象
func TestQueryMap(t *testing.T) {
	//构造查询用的finder
	finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo

	//创建分页对象,查询完成后,page对象可以直接给前端分页组件使用
	page := zorm.NewPage()

	//执行查询.如果不想分页,查询所有数据,page传入nil
	listMap, err := zorm.QueryMap(ctx, finder, page)
	if err != nil { //标记测试失败
		t.Errorf("错误:%v", err)
	}
	//打印结果
	fmt.Println("总条数:", page.TotalCount, "  列表:", listMap)
}

//TestUpdateNotZeroValue 09.更新struct对象,只更新不为零值的字段.主键必须有值
func TestUpdateNotZeroValue(t *testing.T) {

	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault}),如果txOptions为nil,使用全局DefaultTxOptions
	_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		//声明一个对象的指针,用于更新数据
		demo := &demoStruct{}
		demo.Id = "41b2aa4f-379a-4319-8af9-08472b6e514e"
		demo.UserName = "UpdateNotZeroValue"

		//更新 "sql":"UPDATE t_demo SET userName=? WHERE id=?","args":["UpdateNotZeroValue","41b2aa4f-379a-4319-8af9-08472b6e514e"]
		_, err := zorm.UpdateNotZeroValue(ctx, demo)

		//如果返回的err不是nil,事务就会回滚
		return nil, err
	})
	if err != nil { //标记测试失败
		t.Errorf("错误:%v", err)
	}

}

//TestUpdate 10.更新struct对象,更新所有字段.主键必须有值
func TestUpdate(t *testing.T) {

	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault}),如果txOptions为nil,使用全局DefaultTxOptions
	_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {

		//声明一个对象的指针,用于更新数据
		demo := &demoStruct{}
		demo.Id = "41b2aa4f-379a-4319-8af9-08472b6e514e"
		demo.UserName = "TestUpdate"

		_, err := zorm.Update(ctx, demo)

		//如果返回的err不是nil,事务就会回滚
		return nil, err
	})
	if err != nil { //标记测试失败
		t.Errorf("错误:%v", err)
	}
}

//TestUpdateFinder 11.通过finder更新,zorm最灵活的方式,可以编写任何更新语句,甚至手动编写insert语句
func TestUpdateFinder(t *testing.T) {
	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault}),如果txOptions为nil,使用全局DefaultTxOptions
	_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		finder := zorm.NewUpdateFinder(demoStructTableName) // UPDATE t_demo SET
		//finder = zorm.NewDeleteFinder(demoStructTableName)  // DELETE FROM t_demo
		//finder = zorm.NewFinder().Append("UPDATE").Append(demoStructTableName).Append("SET") // UPDATE t_demo SET
		finder.Append("userName=?,active=?", "TestUpdateFinder", 1).Append("WHERE id=?", "41b2aa4f-379a-4319-8af9-08472b6e514e")

		//更新 "sql":"UPDATE t_demo SET  userName=?,active=? WHERE id=?","args":["TestUpdateFinder",1,"41b2aa4f-379a-4319-8af9-08472b6e514e"]
		_, err := zorm.UpdateFinder(ctx, finder)

		//如果返回的err不是nil,事务就会回滚
		return nil, err
	})
	if err != nil { //标记测试失败
		t.Errorf("错误:%v", err)
	}

}

//TestUpdateEntityMap 12.更新一个EntityMap,主键必须有值
func TestUpdateEntityMap(t *testing.T) {
	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault}),如果txOptions为nil,使用全局DefaultTxOptions
	_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		//创建一个EntityMap,需要传入表名
		entityMap := zorm.NewEntityMap(demoStructTableName)
		//设置主键名称
		entityMap.PkColumnName = "id"
		//Set 设置数据库的字段值,主键必须有值
		entityMap.Set("id", "41b2aa4f-379a-4319-8af9-08472b6e514e")
		entityMap.Set("userName", "TestUpdateEntityMap")
		//更新 "sql":"UPDATE t_demo SET userName=? WHERE id=?","args":["TestUpdateEntityMap","41b2aa4f-379a-4319-8af9-08472b6e514e"]
		_, err := zorm.UpdateEntityMap(ctx, entityMap)

		//如果返回的err不是nil,事务就会回滚
		return nil, err
	})
	if err != nil { //标记测试失败
		t.Errorf("错误:%v", err)
	}

}

//TestDelete 13.删除一个struct对象,主键必须有值
func TestDelete(t *testing.T) {
	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault}),如果txOptions为nil,使用全局DefaultTxOptions
	_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		demo := &demoStruct{}
		demo.Id = "ae9987ac-0467-4fe2-a260-516c89292684"

		//删除 "sql":"DELETE FROM t_demo WHERE id=?","args":["ae9987ac-0467-4fe2-a260-516c89292684"]
		_, err := zorm.Delete(ctx, demo)

		//如果返回的err不是nil,事务就会回滚
		return nil, err
	})
	if err != nil { //标记测试失败
		t.Errorf("错误:%v", err)
	}

}

//TestProc 14.测试调用存储过程
func TestProc(t *testing.T) {
	demo := &demoStruct{}
	finder := zorm.NewFinder().Append("call testproc(?) ", "u_10001")
	zorm.QueryRow(ctx, finder, demo)
	fmt.Println(demo)
}

//TestFunc 15.测试调用自定义函数
func TestFunc(t *testing.T) {
	userName := ""
	finder := zorm.NewFinder().Append("select testfunc(?) ", "u_10001")
	zorm.QueryRow(ctx, finder, &userName)
	fmt.Println(userName)
}

//TestOther 16.其他的一些说明.非常感谢您能看到这一行
func TestOther(t *testing.T) {

	//场景1.多个数据库.通过对应数据库的dbDao,调用BindContextDBConnection函数,把这个数据库的连接绑定到返回的ctx上,然后把ctx传递到zorm的函数即可.
	newCtx, err := dbDao.BindContextDBConnection(ctx)
	if err != nil { //标记测试失败
		t.Errorf("错误:%v", err)
	}

	finder := zorm.NewSelectFinder(demoStructTableName)
	//把新产生的newCtx传递到zorm的函数
	list, _ := zorm.QueryMap(newCtx, finder, nil)
	fmt.Println(list)

	//场景2.单个数据库的读写分离.设置读写分离的策略函数.
	zorm.FuncReadWriteStrategy = myReadWriteStrategy

	//场景3.如果是多个数据库,每个数据库还读写分离,按照 场景1 处理

}

//单个数据库的读写分离的策略 rwType=0 read,rwType=1 write
func myReadWriteStrategy(rwType int) *zorm.DBDao {
	//根据自己的业务场景,返回需要的读写dao,每次需要数据库的连接的时候,会调用这个函数
	return dbDao
}

//---------------------------------//

//实现CustomDriverValueConver接口,扩展自定义类型,例如 达梦数据库text类型,映射出来的是dm.DmClob类型,无法使用string类型直接接收
type CustomDMText struct{}
//GetDriverValue 根据数据库列类型,实体类属性类型,Finder对象,返回driver.Value的实例
//如果无法获取到structFieldType,例如Map查询,会传入nil
//如果返回值为nil,接口扩展逻辑无效,使用原生的方式接收数据库字段值
func (dmtext CustomDMText) GetDriverValue(columnType *sql.ColumnType, structFieldType reflect.Type, finder *zorm.Finder) (driver.Value, error) {
	return &dm.DmClob{}, nil
}
//ConverDriverValue 数据库列类型,实体类属性类型,GetDriverValue返回的driver.Value的临时接收值,Finder对象
//如果无法获取到structFieldType,例如Map查询,会传入nil
//返回符合接收类型值的指针,指针,指针!!!!
func (dmtext CustomDMText) ConverDriverValue(columnType *sql.ColumnType, structFieldType reflect.Type, tempDriverValue driver.Value, finder *zorm.Finder) (interface{}, error) {
	dmClob, _ := tempDriverValue.(*dm.DmClob)
	dmlen, _ := dmClob.GetLength()
	strInt64 := strconv.FormatInt(dmlen, 10)
	dmlenInt, _ := strconv.Atoi(strInt64)
	str, _ := dmClob.ReadString(1, dmlenInt)
	return &str, nil
}
//CustomDriverValueMap 用于配置driver.Value和对应的处理关系,key是 drier.Value 的字符串,例如 *dm.DmClob
//一般是放到init方法里进行添加
zorm.CustomDriverValueMap["*dm.DmClob"] = CustomDMText{}

性能压测

测试代码:https://github.com/alphayan/goormbenchmark

指标说明 总时间,平均每次纳秒数,平均每次分配的内存,平均每次内存分配次数

更新性能zorm,gorm,xorm相当.读取性能zorm比gorm,xorm快一倍

2000 times - Insert
      zorm:     9.05s      4524909 ns/op    2146 B/op     33 allocs/op
      gorm:     9.60s      4800617 ns/op    5407 B/op    119 allocs/op
      xorm:    12.63s      6315205 ns/op    2365 B/op     56 allocs/op

    2000 times - BulkInsert 100 row
      xorm:    23.89s     11945333 ns/op  253812 B/op   4250 allocs/op
      gorm:     Don't support bulk insert - https://github.com/jinzhu/gorm/issues/255
      zorm:     Don't support bulk insert

    2000 times - Update
      xorm:     0.39s       195846 ns/op    2529 B/op     87 allocs/op
      zorm:     0.51s       253577 ns/op    2232 B/op     32 allocs/op
      gorm:     0.73s       366905 ns/op    9157 B/op    226 allocs/op

  2000 times - Read
      zorm:     0.28s       141890 ns/op    1616 B/op     43 allocs/op
      gorm:     0.45s       223720 ns/op    5931 B/op    138 allocs/op
      xorm:     0.55s       276055 ns/op    8648 B/op    227 allocs/op

  2000 times - MultiRead limit 1000
      zorm:    13.93s      6967146 ns/op  694286 B/op  23054 allocs/op
      gorm:    26.40s     13201878 ns/op 2392826 B/op  57031 allocs/op
      xorm:    30.77s     15382967 ns/op 1637098 B/op  72088 allocs/op
展开阅读全文

代码

的 Gitee 指数为
超过 的项目

评论 (34)

加载中
请问用结构体update的时候空字符串是传还是不传这个问题有解决不?
02/19 17:40
回复
举报
光石头软件作者
zorm是通过UpdateNotZeroValue函数实现的,不更新零值的字段
02/19 18:07
回复
举报
太复杂了,用sqlbuilder直接生成sql会比这个快的多,或则直接执行sql,在具体的也许场景里几乎用不到orm。相比较而言还不如用sqlbuilder或则模板构造sql。java那一套太笨重了。xorm也支持事务传播机制,我记得
2020/04/05 16:29
回复
举报
光石头软件作者
拼接sql是个苦力活,容易出错,使用也不方便,对象映射还是刚需的.xorm的事务传播是自己传递参数,没有统一规范,不同的开发人员实现的风格也会不同,属于用户自定义实现.
2020/04/05 17:58
回复
举报
有个库叫xormplus/xorm直接实现了spring的那一套事务传播机制,都好几年了
2020/04/05 18:58
回复
举报
光石头软件作者
它是传递的session,没有强制性,如果不传,就不能支持了,开发人员标准不统一的
2020/04/05 19:00
回复
举报
光石头软件作者
zorm要比xorm和gorm简单多啦,API要比他们少的多,概念性的东西也少的多
2020/04/05 18:06
回复
举报
只用sqlbuilder和sql操作,xorm,gorm,sqlx的api都很少,用go的时候强行orm多余,最多返回结果直接和struct映射,这东西,几个库都实现了
2020/04/05 18:57
回复
举报
光石头软件作者
还是要考虑兼容数据库分页,主键自增或者序列,使用map保存和map接收返回值,事务处理以及传播,读写分离以及多库.....这些都是要实现的呀
2020/04/05 19:03
回复
举报
这些几年前就有很多实现了,我们现在用的我们的内部库。只是看到最近很多从java过来的套用以前java的东西,感觉是对go最大的误解。没事,我也就是看你的项目多了一句嘴而已,你继续你的项目,百花齐放挺好。另外之前看过xorm也实现了读写分离,不过小项目在这一层实现可以,大项目不建议耦合在这一层
2020/04/05 19:07
回复
举报
光石头软件作者
还是建议先跑一遍,再考虑是不是java那套东西呀 zorm是函数一等,完全符合go的设计思想的,还是建议手动跑一下呢
2020/04/05 19:12
回复
举报
主要是我看了你的测试数据有点感慨,几年前我们当时也在做开源库调研的时候做过测试,那时候直接执行sql的性能都是比orm快一倍的,xorm,gorm,beedb,gdb,sqlx好多库。xorm,gorm这种重orm的库自己和自己比较也是,所以就在评论里写了那第一个评论。
2020/04/05 19:15
回复
举报
光石头软件作者
回复 @NoneObject : 是啊,现在的xorm和gorm的确很慢啊 ,zorm已经比他们好多啦,这个还是要均衡考虑的,直接原生sql不使用struct反射也不合适
2020/04/05 19:18
回复
举报
回复 @NoneObject : 真要需要性能的时候,基本都是直接舍弃orm方式的
2020/04/05 19:18
回复
举报
光石头软件作者
回复 @NoneObject : 嗯,zorm有map的方式,就绕过反射了,和手动拼写sql相差不大,但是api比较友好一些,如果还是嫌慢,可以直接在finder里写原生的sql,这个就是原生的性能了
2020/04/05 19:20
回复
举报
回复 @光石头 : 使用xorm,gorm之类的是一样的有直接执行raw的方式,最后结果映射到struct,其实大道至简。前面不用orm,采用sqlbuilder方式在go中更合适些,sqlbuilder在api上其实和orm差不多,最后就是结果反射到struct,这一步几个库都差不多。目前go的数据库框架库主要耗时就是前面的orm翻译sql和最终结果反射到struct,其他的中间数据库处理过程耗时各库基本一样的。所以基本上最后一步大家都需要,而第一步可以不需要
2020/04/05 19:24
回复
举报
回复 @光石头 : 其实各库都有map的方式,几个库的源码我都读过,包括后来出现的goframe那个库,这部分功能各库基本上是差不多的
2020/04/05 19:26
回复
举报
光石头软件作者
回复 @NoneObject : zorm的finder就是sql的载体,也就是sqlbuilder,是拼接的原生sql,不需要翻译的.返回的时候如果性能要求,可以变成map,不反射到struct
2020/04/05 19:26
回复
举报
回复 @光石头 : 这个功能那几个库也有。估计你没测过。其实现在go的库雷同度挺多的,不过目前确实没有一个比较有统治力的库,包括我们自己后来也不用开源的那几个自己实现了一套内部库。其实go在数据库处理这方面的开源力量挺散挺弱的,相对于其他领域的开源库
2020/04/05 19:30
回复
举报
光石头软件作者
回复 @NoneObject : 甚至可以在finder里Append 原生insert sql语句,我也是一直使用原生sql,比较排斥gorm,xorm 那样用api再造一套sql语法
2020/04/05 19:31
回复
举报
光石头软件作者
回复 @NoneObject : 你们內部库主要侧重哪些功能呀,大佬提点一下啊,我好改进zorm
2020/04/05 19:33
回复
举报
我们实现的那个正常的orm功能都有,加上了sql处理部分,主要是像beetl学习了下,读写分离,事务这些都有。spring那一套事务的东西都移植了。另外缓存方面,xorm原来那个缓存有点弱,还有bug。我们几年前选型的xorm。另外针对数据库函数和存储过程调用有加强。动态sql的外调和反调等。这是基础组件库的同事开发的,不过业务组实际使用的时候,orm的功能基本都不用。
2020/04/05 19:42
回复
举报
好奇怪,oschina安卓客户端好像有bug,每次回复都不能接着你的留言评论。很高兴和你讨论。就是有时候看信息的时候好乱⁼̴̤̆ ꇴ ⁼̴̤̆
2020/04/05 19:44
回复
举报
光石头软件作者
嗯,都差不多,大道至简,直接撸sql吧
2020/04/05 19:46
回复
举报
弱弱地问下如何支持分布式的事务
2020/03/30 08:32
回复
举报
光石头软件作者
zorm实现了标准的数据库事务,目前并未原生实现分布式事务,需要业务和第三方实现配合
2020/03/30 10:03
回复
举报
光石头软件作者
已经有计划集成seata-go了
02/11 09:17
回复
举报
尽快完善相关中文文档吧,例子要详细,才会有人用的,加油
2020/03/25 18:05
回复
举报
光石头软件作者
多谢支持,文档会尽快完善
2020/03/26 11:57
回复
举报
光石头软件作者
2020/03/27 14:52
回复
举报
不要走java orm的老路
2020/03/25 11:38
回复
举报
光石头软件作者
不会的
2020/03/25 13:04
回复
举报
java orm有什么问题?
01/25 14:47
回复
举报
光石头软件作者
java的ORM基本都是把sql语法再翻译一遍,一堆堆的对象,性能低下.xorm和gorm其实也是在抄hibernate,光看帮助文档就头大,一个orm而已,干嘛要搞这么复杂?
02/11 09:10
回复
举报
更多评论
发表了资讯
03/02 17:08

zorm 1.4.9 发布

zorm是golang轻量级ORM,零依赖,支持达梦(dm),金仓(kingbase),神通(shentong),南通(gbase),mysql,postgresql,oracle,mssql,sqlite数据库。 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,主体2500行,零依赖4200行,注释详细,方便定制修改 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sql...

6
2
发表了资讯
02/16 18:06

zorm 1.4.8 发布,优化字段名称驼峰映射

zorm是golang轻量级ORM,零依赖,支持达梦(dm),金仓(kingbase),神通(shentong),南通(gbase),mysql,postgresql,oracle,mssql,sqlite数据库。 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,主体2500行,零依赖4200行,注释详细,方便定制修改 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sql...

4
3
发表了资讯
02/14 09:58

zorm 1.4.7 发布,情人节来一版更新

zorm是golang轻量级ORM,零依赖,支持达梦(dm),金仓(kingbase),神通(shentong),南通(gbase),mysql,postgresql,oracle,mssql,sqlite数据库。 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,主体2500行,零依赖4200行,注释详细,方便定制修改 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sql...

0
1
发表了资讯
02/12 08:49

zorm 1.4.6 发布,千行代码,胜他十万,牛气冲天,零依赖

zorm是golang轻量级ORM,零依赖,支持达梦(dm),金仓(kingbase),神通(shentong),南通(gbase),mysql,postgresql,oracle,mssql,sqlite数据库。 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,主体2500行,零依赖4200行,注释详细,方便定制修改 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sql...

4
16
发表于数据库专区
02/08 15:30

zorm 1.4.5 发布,鼠年封版,欢迎打脸

zorm是golang轻量级ORM,支持达梦(dm),金仓(kingbase),神通(shentong),南通(gbase),mysql,postgresql,oracle,mssql,sqlite数据库。 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2500行,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite,dm(达梦),kingbas...

1
4
发表了资讯
02/06 08:49

zorm 1.4.4 发布,第二个艰难的决定

zorm是golang轻量级ORM,支持达梦(dm),金仓(kingbase),神通(shentong),南通(gbase),mysql,postgresql,oracle,mssql,sqlite数据库。 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2500行,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite,dm(达梦),kingbas...

2
0
发表了资讯
02/05 10:41

zorm 1.4.3 发布,完成国产四库的适配

zorm是golang轻量级ORM,支持达梦(dm),金仓(kingbase),神通(shentong),南通(gbase),mysql,postgresql,oracle,mssql,sqlite数据库。 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2500行,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite,dm(达梦),kingbas...

14
9
发表了资讯
01/31 18:52

zorm 1.4.2 发布,一个艰难的决定

zorm是golang轻量级ORM,支持达梦(dm),金仓(kingbase),神通(shentong),mysql,postgresql,oracle,mssql,sqlite数据库。 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2400行,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite,dm(达梦),kingbase(人大金仓)...

5
4
发表于数据库专区
01/25 22:18

zorm 1.4.1 发布,自定义字段映射逻辑

zorm是golang轻量级ORM,支持达梦(dm),人大金仓(kingbase),mysql,postgresql,oracle,mssql,sqlite数据库. 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2000行左右,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite,dm(达梦),kingbase(人大金仓) 支持数据...

0
3
发表于数据库专区
01/24 13:28

zorm 1.4.0 发布,长期维护版本

zorm 1.4.0 发布了。zorm 是一个 Golang 开发的轻量级 ORM,支持达梦(dm)、人大金仓(kingbase) 、mysql、postgresql、oracle、mssql、sqlite 数据库 。 最近集中精力优化了代码,目前总计代码2210行,中英双语的详细注释,参见代码质量分析:https://gitee.com/chunanyong/zorm/quality_analyses?platform=sonar_qube 转眼zorm也已经在生产环境跑了一年,v1.4.0版本为长期维护版本,会长期维护和优化,各位大佬可以放心使用. 更新内容如...

2
3
发表于数据库专区
01/22 20:24

zorm 1.3.9 发布,简化从 xorm/gorm 迁移

zorm是golang轻量级ORM,支持达梦(dm),人大金仓(kingbase)数据库. 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2000行左右,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite,dm(达梦),kingbase(人大金仓) 支持数据库读写分离 更新性能zorm,gorm,xorm相当...

4
3
发表于数据库专区
01/20 22:06

zorm 1.3.7 发布,腊八节版本

zorm是golang轻量级ORM,支持达梦(dm),人大金仓(kingbase)数据库. 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2000行左右,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite,dm(达梦),kingbase(人大金仓) 支持数据库读写分离 更新性能zorm,gorm,xorm相当...

2
5
发表于开发技能专区
2020/12/31 19:02

zorm 1.3.5 发布,新年无 BUG

zorm是golang轻量级ORM,支持达梦(dm),人大金仓(kingbase)数据库. 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2000行左右,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite,dm(达梦),kingbase(人大金仓) 支持数据库读写分离 更新性能zorm,gorm,xorm相当...

2
3
发表于数据库专区
2020/12/26 07:19

zorm 1.3.5 发布,送给 Go 的圣诞礼物

golang轻量级ORM,支持达梦(dm),人大金仓(kingbase)数据库. 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2000行左右,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite,dm(达梦),kingbase(人大金仓) 支持数据库读写分离 更新性能zorm,gorm,xorm相当. 读取...

4
6
发表于数据库专区
2020/12/17 19:19

zorm 1.3.4 发布,支持达梦、人大金仓的 Golang ORM

golang轻量级ORM,支持达梦(dm),人大金仓(kingbase)数据库. 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2000行左右,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite,dm(达梦),kingbase(人大金仓) 支持数据库读写分离 更新性能zorm,gorm,xorm相当. 读取...

0
7
发表于数据库专区
2020/12/16 00:45

zorm 1.3.3 发布,支持达梦数据库的 Golang ORM

zorm,golang 轻量级 ORM,readygo子项目 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2000行左右,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite,dm(达梦) 支持数据库读写分离 更新性能zorm,gorm,xorm相当. 读取性能zorm比gorm,xorm快一倍 测试用例即...

8
4
发表于数据库专区
2020/12/11 21:09

zorm 1.3.2 发布,Golang 轻量级 ORM

zorm,golang 轻量级 ORM,readygo子项目 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2000行左右,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite 支持数据库读写分离 更新性能zorm,gorm,xorm相当. 读取性能zorm比gorm,xorm快一倍 测试用例即文档: h...

15
4
发表于服务端专区
2020/04/05 10:33

zorm 1.3.1 发布,Golang 轻量级 ORM

zorm,golang 轻量级 ORM,readygo子项目 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2000行左右,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite 支持数据库读写分离 更新性能zorm,gorm,xorm相当. 读取性能zorm比gorm,xorm快一倍 测试用例即文档: h...

0
7
发表于开发技能专区
2020/03/30 08:11

zorm 1.3.0 发布,Golang 轻量级 ORM

zorm,golang 轻量级 ORM,readygo子项目 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生sql语句编写,是springrain的精简和优化. 自带代码生成器 代码精简,总计2000行左右,注释详细,方便定制修改. 支持事务传播,这是zorm诞生的主要原因 支持mysql,postgresql,oracle,mssql,sqlite 支持数据库读写分离 更新性能zorm,gorm,xorm相当. 读取性能zorm比gorm,xorm快一倍 测试用例即文档: h...

4
4
发表于服务端专区
2020/03/27 08:09

zorm 1.2.9 发布,Golang 轻量级 ORM, 测试用例即文档

zorm,golang 轻量级 ORM,readygo子项目 更新内容如下: IEntityMap支持主键自增或主键序列 更新方法返回影响的行数affected 修复 查询IEntityMap时数据库无记录出现异常的bug 测试用例即文档 https://gitee.com/chunanyong/zorm/blob/master/test/BaseDao_test.go 源码地址:https://gitee.com/chunanyong/zorm go get gitee.com/chunanyong/zorm 基于原生 sql 语句编写,是 springrain 的精简和优化 自带代码生成器 代码精...

0
14
没有更多内容
加载失败,请刷新页面
点击加载更多
加载中
下一页
暂无内容
暂无内容
34 评论
57 收藏
分享
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部