zorm

package module
v1.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 4, 2020 License: Apache-2.0 Imports: 18 Imported by: 33

README

zorm

介绍

golang轻量级ORM,readygo子项目
API文档

源码地址: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快一倍

生产使用参考 UserStructService.go

测试用例

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

// zorm 使用原生的sql语句,没有对sql语法做限制.语句使用Finder作为载体
// 占位符统一使用?,zorm会根据数据库类型,自动替换占位符,例如postgresql数据库把?替换成$1,$2...
// 为了保持数据库兼容性,分页语句必须有order by
// 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(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
  `active` int(0) NOT NULL DEFAULT 1 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"`

	//------------------数据库字段结束,自定义字段写在下面---------------//

}

//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...
// 为了保持数据库兼容性,分页语句必须有order by
// 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的函数

	//dbDaoConfig 数据库的配置
	dbDaoConfig := zorm.DataSourceConfig{
		//DSN 数据库的连接字符串
		DSN: "root:root@tcp(127.0.0.1:3306)/readygo?charset=utf8&parseTime=true",
		//DriverName 数据库驱动名称,和DBType对应,一个数据库可以有多个驱动(DriverName)
		DriverName: "mysql",
		//DBType 数据库类型(mysql,postgresql,oracle,mssql,sqlite),zorm判断方言的依据,一个数据库可以有多个驱动(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,
	}

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

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

	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	_, 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)
	}
}

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

	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	_, 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)
	}
}

//TestQuery 04.测试查询一个struct对象
func TestQuery(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})

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

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

//TestQueryMap 05.测试查询map接收结果,用于不太适合struct的场景,比较灵活
func TestQueryMap(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.QueryMap(ctx, finder)

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

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

	//构造查询用的finder
	finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
	//为了保证数据库迁移,分页语句必须要有order by
	finder.Append("order by id asc")

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

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

//TestQueryMapSlice 07.测试查询map列表,用于不方便使用struct的场景,一条记录是一个map对象
func TestQueryMapSlice(t *testing.T) {
	//构造查询用的finder
	finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
	//为了保证数据库迁移,分页语句必须要有order by
	finder.Append("order by id asc")

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

	//执行查询
	listMap, err := zorm.QueryMapSlice(ctx, finder, page)
	if err != nil { //标记测试失败
		t.Errorf("错误:%v", err)
	}
	//打印结果
	fmt.Println("总条数:", page.TotalCount, "  列表:", listMap)
}

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

	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	_, 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 09.更新struct对象,更新所有字段.主键必须有值
func TestUpdate(t *testing.T) {

	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	_, 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 10.通过finder更新,zorm最灵活的方式,可以编写任何更新语句,甚至手动编写insert语句
func TestUpdateFinder(t *testing.T) {
	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	_, 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 11.更新一个EntityMap,主键必须有值
func TestUpdateEntityMap(t *testing.T) {
	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	_, 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 12.删除一个struct对象,主键必须有值
func TestDelete(t *testing.T) {
	//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
	_, 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)
	}

}

//TestOther 13.其他的一些说明.非常感谢您能看到这一行
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).Append("order by id ")
	//把新产生的newCtx传递到zorm的函数
	list, _ := zorm.QueryMapSlice(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
}




性能压测

测试代码: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

Documentation

Overview

Package zorm 使用原生的sql语句,没有对sql语法做限制.语句使用Finder作为载体 占位符统一使用?,zorm会根据数据库类型,语句执行前会自动替换占位符,postgresql 把?替换成$1,$2...;mssql替换成@P1,@p2...;orace替换成:1,:2... 为了保持数据库兼容性,分页语句必须有order by zorm使用 ctx context.Context 参数实现事务传播,ctx从web层传递进来即可,例如gin的c.Request.Context() zorm的事务操作需要显示使用zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {})开启

Index

Constants

This section is empty.

Variables

View Source
var FuncGenerateStringID func() string = generateStringID

FuncGenerateStringID 默认生成字符串ID的函数.方便自定义扩展

View Source
var FuncLogError func(err error) = defaultLogError

FuncLogError 记录error日志

View Source
var FuncLogPanic func(err error) = defaultLogPanic

FuncLogPanic 记录panic日志,默认使用ZormErrorLog实现

View Source
var FuncPrintSQL func(sqlstr string, args []interface{}) = defaultPrintSQL

FuncPrintSQL 打印sql语句和参数

View Source
var FuncReadWriteStrategy func(rwType int) *DBDao = getDefaultDao

FuncReadWriteStrategy 单个数据库的读写分离的策略,用于外部复写实现自定义的逻辑,rwType=0 read,rwType=1 write 不要放到BaseDao里,BindContextDBConnection已经是指定数据库的连接了,和这个函数会冲突.就作为单数据库读写分离的处理方式,不归属到BaseDao

View Source
var LogCalldepth = 4

LogCalldepth 记录日志调用层级,用于定位到业务层代码

Functions

func Delete added in v1.3.1

func Delete(ctx context.Context, entity IEntityStruct) (int, error)

Delete 根据主键删除一个对象.必须是*IEntityStruct类型 ctx不能为nil,参照使用zorm.Transaction方法传入ctx.也不要自己构建DBConnection affected影响的行数,如果异常或者驱动不支持,返回-1

func Insert added in v1.3.1

func Insert(ctx context.Context, entity IEntityStruct) (int, error)

Insert 保存Struct对象,必须是*IEntityStruct类型 ctx不能为nil,参照使用zorm.Transaction方法传入ctx.也不要自己构建DBConnection affected影响的行数,如果异常或者驱动不支持,返回-1

func InsertEntityMap added in v1.3.1

func InsertEntityMap(ctx context.Context, entity IEntityMap) (int, error)

InsertEntityMap 保存*IEntityMap对象.使用Map保存数据,用于不方便使用struct的场景,如果主键是自增或者序列,不要entityMap.Set主键的值 ctx不能为nil,参照使用zorm.Transaction方法传入ctx.也不要自己构建DBConnection affected影响的行数,如果异常或者驱动不支持,返回-1

func Query added in v1.3.1

func Query(ctx context.Context, finder *Finder, entity interface{}) error

Query 不要偷懒调用QuerySlice返回第一条,1.需要构建一个selice,2.调用方传递的对象其他值会被抛弃或者覆盖. 根据Finder和封装为指定的entity类型,entity必须是*struct类型或者基础类型的指针.把查询的数据赋值给entity,所以要求指针类型 context必须传入,不能为空

func QueryMap

func QueryMap(ctx context.Context, finder *Finder) (map[string]interface{}, error)

QueryMap 根据Finder查询,封装Map context必须传入,不能为空

func QueryMapSlice added in v1.3.1

func QueryMapSlice(ctx context.Context, finder *Finder, page *Page) ([]map[string]interface{}, error)

QueryMapSlice 根据Finder查询,封装Map数组 根据数据库字段的类型,完成从[]byte到golang类型的映射,理论上其他查询方法都可以调用此方法,但是需要处理sql.Nullxxx等驱动支持的类型 context必须传入,不能为空

func QuerySlice added in v1.3.1

func QuerySlice(ctx context.Context, finder *Finder, rowsSlicePtr interface{}, page *Page) error

QuerySlice 不要偷懒调用QueryMapList,需要处理sql驱动支持的sql.Nullxxx的数据类型,也挺麻烦的 根据Finder和封装为指定的entity类型,entity必须是*[]struct类型,已经初始化好的数组,此方法只Append元素,这样调用方就不需要强制类型转换了 context必须传入,不能为空

func Transaction

func Transaction(ctx context.Context, doTransaction func(ctx context.Context) (interface{}, error)) (interface{}, error)

Transaction 的示例代码

  //匿名函数return的error如果不为nil,事务就会回滚
  zorm.Transaction(ctx context.Context,func(ctx context.Context) (interface{}, error) {

	  //业务代码

	  //return的error如果不为nil,事务就会回滚
      return nil, nil
  })

事务方法,隔离dbConnection相关的API.必须通过这个方法进行事务处理,统一事务方式 如果入参ctx中没有dbConnection,使用defaultDao开启事务并最后提交 如果入参ctx有dbConnection且没有事务,调用dbConnection.begin()开启事务并最后提交 如果入参ctx有dbConnection且有事务,只使用不提交,有开启方提交事务 但是如果遇到错误或者异常,虽然不是事务的开启方,也会回滚事务,让事务尽早回滚 在多库的场景,手动获取dbConnection,然后帮定到一个新的context,传入进来 不要去掉匿名函数的context参数,因为如果Transaction的context中没有dbConnection,会新建一个context并放入dbConnection,此时的context指针已经变化,不能直接使用Transaction的context参数 bug(springrain)如果有大神修改了匿名函数内的参数名,例如改为ctx2,这样业务代码实际使用的是Transaction的context参数,如果为没有dbConnection,会抛异常,如果有dbConnection,实际就是一个对象.影响有限.也可以把匿名函数抽到外部 return的error如果不为nil,事务就会回滚

func Update added in v1.3.1

func Update(ctx context.Context, entity IEntityStruct) (int, error)

Update 更新struct所有属性,必须是*IEntityStruct类型 ctx不能为nil,参照使用zorm.Transaction方法传入ctx.也不要自己构建DBConnection

func UpdateEntityMap

func UpdateEntityMap(ctx context.Context, entity IEntityMap) (int, error)

UpdateEntityMap 更新*IEntityMap对象.用于不方便使用struct的场景,主键必须有值 ctx不能为nil,参照使用zorm.Transaction方法传入ctx.也不要自己构建DBConnection affected影响的行数,如果异常或者驱动不支持,返回-1

func UpdateFinder

func UpdateFinder(ctx context.Context, finder *Finder) (int, error)

UpdateFinder 更新Finder语句 ctx不能为nil,参照使用zorm.Transaction方法传入ctx.也不要自己构建DBConnection affected影响的行数,如果异常或者驱动不支持,返回-1

func UpdateNotZeroValue added in v1.3.1

func UpdateNotZeroValue(ctx context.Context, entity IEntityStruct) (int, error)

UpdateNotZeroValue 更新struct不为默认零值的属性,必须是*IEntityStruct类型,主键必须有值 ctx不能为nil,参照使用zorm.Transaction方法传入ctx.也不要自己构建DBConnection

Types

type DBDao added in v1.3.1

type DBDao struct {
	// contains filtered or unexported fields
}

DBDao 数据库操作基类,隔离原生操作数据库API入口,所有数据库操作必须通过DBDao进行

func NewDBDao added in v1.3.1

func NewDBDao(config *DataSourceConfig) (*DBDao, error)

NewDBDao 创建dbDao,一个数据库要只执行一次,业务自行控制 第一个执行的数据库为 defaultDao,后续zorm.xxx方法,默认使用的就是defaultDao

func (*DBDao) BindContextDBConnection added in v1.3.1

func (dbDao *DBDao) BindContextDBConnection(parent context.Context) (context.Context, error)

BindContextDBConnection 多库的时候,通过dbDao创建DBConnection绑定到子context,返回的context就有了DBConnection parent 不能为空

type DataSourceConfig

type DataSourceConfig struct {
	//DSN dataSourceName 连接字符串
	DSN string
	//DriverName 数据库驱动名称,和DBType对应,一个数据库可以有多个驱动(DriverName)
	DriverName string
	//DBType 数据库类型(mysql,postgresql,oracle,mssql,sqlite),zorm判断方言的依据,一个数据库可以有多个驱动(DriverName)
	DBType string
	//PrintSQL 是否打印SQL语句.使用zorm.ZormPrintSQL记录SQL
	PrintSQL bool
	//MaxOpenConns 数据库最大连接数 默认50
	MaxOpenConns int
	//MaxIdleConns 数据库最大空闲连接数 默认50
	MaxIdleConns int
	//ConnMaxLifetimeSecond 连接存活秒时间. 默认600(10分钟)后连接被销毁重建.避免数据库主动断开连接,造成死连接.MySQL默认wait_timeout 28800秒(8小时)
	ConnMaxLifetimeSecond int
}

DataSourceConfig 数据库连接池的配置

type EntityMap

type EntityMap struct {

	//主键列名
	PkColumnName string
	//兼容主键序列.如果有值,优先级最高
	PkSequence string
	// contains filtered or unexported fields
}

EntityMap IEntityMap的基础实现,可以直接使用或者匿名注入

func NewEntityMap

func NewEntityMap(tbName string) *EntityMap

NewEntityMap 初始化Map,必须传入表名称

func (*EntityMap) GetDBFieldMap

func (entity *EntityMap) GetDBFieldMap() map[string]interface{}

GetDBFieldMap 针对Map类型,记录数据库字段

func (*EntityMap) GetPKColumnName

func (entity *EntityMap) GetPKColumnName() string

GetPKColumnName 获取数据库表的主键字段名称.因为要兼容Map,只能是数据库的字段名称.

func (*EntityMap) GetPkSequence added in v1.2.9

func (entity *EntityMap) GetPkSequence() string

GetPkSequence Oracle和pgsql没有自增,主键使用序列.优先级高于GetPKColumnName方法

func (*EntityMap) GetTableName

func (entity *EntityMap) GetTableName() string

GetTableName 获取表名称

func (*EntityMap) Set

func (entity *EntityMap) Set(key string, value interface{}) map[string]interface{}

Set 设置数据库字段

type EntityStruct

type EntityStruct struct {
}

EntityStruct IBaseEntity 的基础实现,所有的实体类都匿名注入.这样就类似实现继承了,如果接口增加方法,调整这个默认实现即可

func (*EntityStruct) GetPKColumnName

func (entity *EntityStruct) GetPKColumnName() string

GetPKColumnName 获取数据库表的主键字段名称.因为要兼容Map,只能是数据库的字段名称.

func (*EntityStruct) GetPkSequence

func (entity *EntityStruct) GetPkSequence() string

GetPkSequence Oracle和pgsql没有自增,主键使用序列.优先级高于GetPKColumnName方法

type Finder

type Finder struct {

	//注入检查,默认true 不允许SQL注入的 ' 单引号
	InjectionCheck bool
	//CountFinder 自定义的查询总条数Finder,使用指针默认为nil.主要是为了在group by等复杂情况下,为了性能,手动编写总条数语句
	CountFinder *Finder
	//是否自动查询总条数,默认true.同时需要Page不为nil,才查询总条数
	SelectTotalCount bool
	// contains filtered or unexported fields
}

Finder 查询数据库的载体,所有的sql语句都要通过Finder执行.

func NewDeleteFinder

func NewDeleteFinder(tableName string) *Finder

NewDeleteFinder 根据表名初始化删除的Finder, DELETE FROM tableName

func NewFinder

func NewFinder() *Finder

NewFinder 初始化一个Finder,生成一个空的Finder

func NewSelectFinder

func NewSelectFinder(tableName string, strs ...string) *Finder

NewSelectFinder 根据表名初始化查询的Finder NewSelectFinder("tableName") SELECT * FROM tableName NewSelectFinder("tableName", "id,name") SELECT id,name FROM tableName

func NewUpdateFinder

func NewUpdateFinder(tableName string) *Finder

NewUpdateFinder 根据表名初始化更新的Finder, UPDATE tableName SET

func (*Finder) Append

func (finder *Finder) Append(s string, values ...interface{}) *Finder

Append 添加SQL和参数的值,第一个参数是语句,后面的参数[可选]是参数的值,顺序要正确. 例如: finder.Append(" and id=? and name=? ",23123,"abc") 只拼接SQL,例如: finder.Append(" and name=123 ")

func (*Finder) AppendFinder

func (finder *Finder) AppendFinder(f *Finder) (*Finder, error)

AppendFinder 添加另一个Finder finder.AppendFinder(f)

func (*Finder) GetSQL

func (finder *Finder) GetSQL() (string, error)

GetSQL 返回Finder封装的SQL语句

type IEntityMap

type IEntityMap interface {
	//获取表名称
	GetTableName() string
	//获取数据库表的主键字段名称.因为要兼容Map,只能是数据库的字段名称.
	GetPKColumnName() string
	//兼容主键序列.如果有值,优先级最高
	GetPkSequence() string
	//针对Map类型,记录数据库字段
	GetDBFieldMap() map[string]interface{}
	//设置数据库字段的值
	Set(key string, value interface{}) map[string]interface{}
}

IEntityMap 使用Map保存数据,用于不方便使用struct的场景,如果主键是自增或者序列,不要entityMap.Set主键的值

type IEntityStruct

type IEntityStruct interface {
	//获取表名称
	GetTableName() string
	//获取数据库表的主键字段名称.因为要兼容Map,只能是数据库的字段名称.
	GetPKColumnName() string
	//兼容主键序列.如果有值,优先级最高
	GetPkSequence() string
}

IEntityStruct structe实体类的接口,所有的struct实体类都要实现这个接口

type Page

type Page struct {
	//当前页码,从1开始
	PageNo int
	//每页多少条,默认20条
	PageSize int
	//数据总条数
	TotalCount int
	//总共多少页
	PageCount int
	//是否是第一页
	FirstPage bool
	//是否有上一页
	HasPrev bool
	//是否有下一页
	HasNext bool
	//是否是最后一页
	LastPage bool
}

Page 分页对象

func NewPage

func NewPage() *Page

NewPage 创建Page对象

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL