daog

package module
v0.0.41 Latest Latest
Warning

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

Go to latest
Published: Jul 13, 2025 License: MIT Imports: 14 Imported by: 15

README

轻量、高性能

daog是轻量级的数据库访问组件,它并不能称之为orm组件,仅仅提供了一组函数用以实现常用的数据库访问功能。 它是高性能的,与原生的使用sql包函数相比,没有性能损耗,这是因为,它并没有使用反射技术,而是使用编译技术把create table sql语句编译成daog需要的go代码。 它目前仅支持mysql。

设计思路来源于java的orm框架sampleGenericDao和protobuf的编译思路。之所以选择编译 而没有使用反射,是因为基于编译的抽象没有性能损耗。

编译组件

compilex 是编译create table语句文件的工具,使用如下语句可以编译:

  ./compilex -i="sql file" -pkg packageName -o xxx/xx

编译完成后,把整个packageName文件夹copy到你的项目中即可。每一个表生成两个文件:

  • 主文件,以表名的驼峰格式命名,包含映射表的struct,和两个元数据对象,主文件不要修改
  • 扩展文件,以表名的驼峰格式+"-ext" 命名,这个文件可以修改,开发者可以自由扩展针对该表的数据访问功能。daog支持分表,分表函数需要在该文件的init函数中设置。

使用

核心概念

使用之前先要了解Datasource、TransContext、TableMeta

Datasource

数据源,用于描述一个mysql database,这儿的database指的是您使用create database创建出来的逻辑库。Datasource提供获链接、关闭库函数,也可以配置在改数据源上操作数据是否要输出执行sql日志。

  • 使用NewDatasource或NewShardingDatasource函数来创建Datasource对象
  • 数据库相关配置使用DbConf描述
TransContext

事务的执行上下文,所有的数据库操作都应该在一个数据上下文中执行,所有操作完成后必须调用Complete函数来结束事务上下文,一旦结束该上下文将不能再被使用。

  • 使用NewTransContext和NewTransContextWithSharding函数来创建事务上下文,二者的区别是是否支持分库分表,分库分表不必同时进行,可以只分库,也可以只分表,不需要的sharding Key传入nil即可。
  • 支持3中事务类型:没有事务、只读事务、写事务,txrequest包定义了对应的常量
  • 必须调用Complete方法来结束事务上下文,一般使用defer语句来结束事务上下文
TableMeta

go struct,用来描述数据表及对应go 对象信息信息,在go程序中一张数据库表需要对应的一个struct来描述,包括:

  • 表名及对应的struct的名称
  • 字段信息:字段名,对应struct的属性信息,数据类型信息
  • 用于根据字段名查找struct对象的属性值或者属性指针,采用该方法避免使用反射来为属性赋值,或者读取属性的值

每张表的TableMeta对象是通过compliex来生成的,无需手工创建

其他概念
Matcher

用于拼接sql条件的工具,直接进行字符串拼接往往会产生错误,而且错误只能在运行时被发现,提供工具来避免这种情况。 Matcher至支持多个条件组合.

  • Matcher内置了eq,like,between,gt,lt等过个快捷条件生成,支持组合新的Matcher,也支持您自己实现新的条件,直接实现 SQLCond接口即可。
  • 使用NewMatcher、NewAndMatcher、NewOrMatcher来创建对象
TableFields

这是逻辑概念,compilex会在每张表对应的主go文件中创建一个匿名struct对象。该对象记录了数据库的字段名称,以便于利用Matcher拼接sql

Modifier

顾名思义,用于update表字段,它描述了一组字段名与对应值对,用于拼接update语句

使用方式

daog提供了两种数据方式形式:

  • 直接使用daog提供的函数,比如:
func Insert[T any](tc *TransContextins *T, meta *TableMeta[T]) (int64, error) 
func QueryListMatcher[T any](tc *TransContext,m Matcher, meta *TableMeta[T]) ([]*T, error)
  • 使用QuickDao接口,该接口支持模板参数,每个编译好的主文件中都有类似GroupInfoDao的变量,该变量是QuickDao[GroupInfo]类型,包含一个实现QuickDao[GroupInfo]的匿名struct对象,可以直接使用它来操作数据库,相对于使用函数,它少传递了TableMeta对象

使用实例

可以参照代码的example

编译create table语句
create table group_info (
    id bigint(20) not null AUTO_INCREMENT primary key,
    `name` varchar(200) not null comment 'user name',
    main_data json not null,
    create_at datetime not null,
    total_amount decimal(10,2) not null
) ENGINE=innodb CHARACTER SET utf8mb4 comment 'group info';

编译出的主代码:

package dal

import (
	"github.com/rolandhe/daog"
	dbtime "github.com/rolandhe/daog/time"
	"github.com/shopspring/decimal"
)

var GroupInfoFields = struct {
	Id string
	Name string
	MainData string
	CreateAt string
	TotalAmount string

}{
	"id",
	"name",
	"main_data",
	"create_at",
	"total_amount",

}

var  GroupInfoMeta = &daog.TableMeta[GroupInfo]{
	InstanceFunc: func() *GroupInfo{
		return &GroupInfo{}
	},
	Table: "group_info",
	Columns: []string {
		"id",
		"name",
		"main_data",
		"create_at",
		"total_amount",

	},
	AutoColumn: "id",
	LookupFieldFunc: func(columnName string,ins *GroupInfo,point bool) any {
		if "id" == columnName {
			if point {
				return &ins.Id
			}
			return ins.Id
		}
		if "name" == columnName {
			if point {
				return &ins.Name
			}
			return ins.Name
		}
		if "main_data" == columnName {
			if point {
				return &ins.MainData
			}
			return ins.MainData
		}
		if "create_at" == columnName {
			if point {
				return &ins.CreateAt
			}
			return ins.CreateAt
		}
		if "total_amount" == columnName {
			if point {
				return &ins.TotalAmount
			}
			return ins.TotalAmount
		}

		return nil
	},
}

var GroupInfoDao daog.QuickDao[GroupInfo] = &struct {
	daog.QuickDao[GroupInfo]
}{
	daog.NewBaseQuickDao(GroupInfoMeta),
}

type GroupInfo struct {
	Id int64
	Name string
	MainData string
	CreateAt dbtime.NormalDatetime
	TotalAmount decimal.Decimal

}

copy到您的工程中

构建全局的Datasource对象
var datasource daog.Datasource

func init() {
	conf := &daog.DbConf{
		DbUrl:  "root:12345678@tcp(localhost:3306)/daog?parseTime=true&timeout=1s&readTimeout=2s&writeTimeout=2s",
		LogSQL: true,
	}
	var err error
	datasource, err = daog.NewDatasource(conf)
	if err != nil {
		log.Fatalln(err)
	}
}
构建事务上下文
// 构建写事务
tc, err := daog.NewTransContext(datasource, txrequest.RequestWrite, "trace-100099")
if err != nil {
    fmt.Println(err)
    return
}
// 构建读事务
tc, err := daog.NewTransContext(datasource, txrequest.RequestReadonly, "trace-100099")
if err != nil {
    fmt.Println(err)
    return
}

// 构建无事务
tc, err := daog.NewTransContext(datasource, txrequest.RequestNone, "trace-100099")
if err != nil {
    fmt.Println(err)
    return
}

函数模式
写表
func create() {
	amount, err := decimal.NewFromString("128.0")
	if err != nil {
		fmt.Println(err)
		return
	}
	t := &dal.GroupInfo{
		Name:        "roland-one",
		MainData:    `{"a":102}`,
		Content:     "hello world!!",
		BinData:     []byte("byte data"),
		CreateAt:    ttypes.NormalDatetime(time.Now()),
		TotalAmount: amount,
		Remark:      *ttypes.FromString("haha"),
	}

	tcCreate := func() (*daog.TransContext, error) {
		return daog.NewTransContext(datasource, txrequest.RequestWrite, "trace-1001")
	}
	daog.AutoTrans(tcCreate, func(tc *daog.TransContext) error {
		affect, err := daog.Insert(tc, t, dal.GroupInfoMeta)
		fmt.Println(affect, t.Id, err)
		if err != nil {
			return err
		}
		t.Name = "rolandx"
		af, err := daog.Update(tc, t, dal.GroupInfoMeta)
		fmt.Println(af, err)
		if err != nil {
			return err
		}
		return nil
	})
}
读取数据
func queryByIds() {
	tcCreate := func() (*daog.TransContext, error) {
		return daog.NewTransContext(datasource, txrequest.RequestReadonly, "trace-1001")
	}
	gs, err := daog.AutoTransWithResult(tcCreate, func(tc *daog.TransContext) ([]*dal.GroupInfo, error) {
		return daog.GetByIds(tc, []int64{1, 2}, dal.GroupInfoMeta)
	})

	if err != nil {
		fmt.Println(err)
	}
	j, _ := json.Marshal(gs)
	fmt.Println("queryByIds", string(j))
	fmt.Println(gs)
}
func queryAll() {
	tc, err := daog.NewTransContext(datasource, txrequest.RequestNone, "trace-1001")
	if err != nil {
		fmt.Println(err)
		return
	}
	// tc 创建后必须马上跟上 defer func, 如果这之间有return或者panic,连接将被泄露
	// 无事务情况下也需要加上这段代码,用于释放底层链接
	// 必须使用匿名函数,不能使用 tc.Complete(err), 因为defer 后面函数的参数在执行defer语句是就会被确定
	defer func() {
		// 注意:后面代码的error都要使用err变量来接收,否则在发生错误的情况下,事务不会被回滚
		tc.CompleteWithPanic(err, recover())
	}()
	gs, err := daog.GetAll(tc, dal.GroupInfoMeta)
	if err != nil {
		fmt.Println(err)
	}
	j, _ := json.Marshal(gs)
	fmt.Println("queryAll", string(j))
	fmt.Println(gs)
}
根据Matcher读取
func queryByMatcher() {
	matcher := daog.NewMatcher().Like(dal.GroupInfoFields.Name, "roland", daog.LikeStyleRight).Lt(dal.GroupInfoFields.Id, 4)
	tcCreate := func() (*daog.TransContext, error) {
		return daog.NewTransContext(datasource, txrequest.RequestNone, "trace-1001")
	}
	gs, err := daog.AutoTransWithResult(tcCreate, func(tc *daog.TransContext) ([]*dal.GroupInfo, error) {
		return daog.QueryListMatcher(tc, matcher, dal.GroupInfoMeta)
	})

	if err != nil {
		fmt.Println(err)
	}
	j, _ := json.Marshal(gs)
	fmt.Println("queryByMatcher", string(j))
	fmt.Println(gs)
}
先读再写
func update() {
	tc, err := daog.NewTransContext(datasource, txrequest.RequestWrite, "trace-100099")
	if err != nil {
		fmt.Println(err)
		return
	}
	// tc 创建后必须马上跟上 defer func, 如果这之间有return或者panic,连接将被泄露
	// 必须使用匿名函数,不能使用 tc.CompleteWithPanic(err), 因为defer 后面函数的参数在执行defer语句是就会被确定
	defer func() {
		// 注意:后面代码的error都要使用err变量来接收,否则在发生错误的情况下,事务不会被回滚
		tc.CompleteWithPanic(err, recover())
	}()
	g, err := daog.GetById(tc, 5, dal.GroupInfoMeta)
	if err != nil {
		fmt.Println(err)
	}
	j, _ := json.Marshal(g)
	fmt.Println("query", string(j))

	g.Name = "Eric"
	af, err := daog.Update(tc, g, dal.GroupInfoMeta)
	fmt.Println(af, err)

}
删除
func deleteById() {
	tcCreate := func() (*daog.TransContext, error) {
		return daog.NewTransContext(datasource, txrequest.RequestWrite, "trace-1001")
	}
	daog.AutoTrans(tcCreate, func(tc *daog.TransContext) error {
		g, err := daog.DeleteById(tc, 2, dal.GroupInfoMeta)
		if err != nil {
			fmt.Println(err)
			return err
		}
		fmt.Println("delete", g)
		return err
	})
}
两种种事务管理
自动委模式

把所有的事务处理代码都内置到一个函数里,当然这个函数可以是匿名函数,也可以是命名函数,然后调用daog.AutoTrans 或者daog.AutoTransWithResult 来执行业务处理函数,同时事务上下文的构建也被内置到一个函数里,这个函数可以是匿名,也可以是命名的。 在这种方式下,事务的创建及最终的提交或回滚不需要再额外处理。使用方式如下,如果你不需要业务返回值,可以调用daog.AutoTrans。

func createUserUseAutoTrans() {
	t := &dal.UserInfo{
		Name:     "roland",
		CreateAt: ttypes.NormalDatetime(time.Now()),
		ModifyAt: *ttypes.FromDatetime(time.Now()),
	}
	affect, err := daog.AutoTransWithResult[int64](func() (*daog.TransContext, error) {
		return daog.NewTransContext(datasource, txrequest.RequestWrite, "trace-1001")
	}, func(tc *daog.TransContext) (int64, error) {
		return daog.Insert(tc, t, dal.UserInfoMeta)
	})
	fmt.Println(affect, t.Id, err)
}
自行处理式

在创建TransContext后,需要手工处理事务的结束,必须通过一个匿名deffer函数来结束事务,匿名函数里调用 tc.CompleteWithPanic(err, recover()) 来最终结束事务。

需要注意的是:

  • err在当前的函数里必须是全局的
  • 每一个会产生err的函数调用,都必须使用该全局err来接收,比如: err = XXX()
  • tc 创建后必须马上跟上 defer func, 如果这之间有return或者panic,连接将被泄露
func queryByMatcherOrder() {
	tc, err := daog.NewTransContext(datasource, txrequest.RequestNone, "trace-1001")
	if err != nil {
		fmt.Println(err)
		return
	}
	// tc 创建后必须马上跟上 defer func, 如果这之间有return或者panic,连接将被泄露
	// 无事务情况下也需要加上这段代码,用于释放底层链接
	// 必须使用匿名函数,不能使用 tc.Complete(err), 因为defer 后面函数的参数在执行defer语句是就会被确定
	defer func() {
		// 注意:后面代码的error都要使用err变量来接收,否则在发生错误的情况下,事务不会被回滚
		tc.CompleteWithPanic(err, recover())
	}()
	matcher := daog.NewMatcher().Like(dal.GroupInfoFields.Name, "roland", daog.LikeStyleLeft).Lt(dal.GroupInfoFields.Id, 4)
	gs, err := daog.QueryListMatcher(tc, matcher, dal.GroupInfoMeta, daog.NewDescOrder(dal.GroupInfoFields.Id))
	if err != nil {
		fmt.Println(err)
	}
	j, _ := json.Marshal(gs)
	fmt.Println("queryByMatcherOrder", string(j))
	fmt.Println(gs)
}

QuickDao接口模式

使用方式和函数模式非常类似,只是少传递TableMeta参数,以下以一个query示例来说明一下。

查询数据
func queryByIdsUsingDao() {
	tcCreate := func() (*daog.TransContext, error) {
		return daog.NewTransContext(datasource, txrequest.RequestReadonly, "trace-1001")
	}
	gs, err := daog.AutoTransWithResult(tcCreate, func(tc *daog.TransContext) ([]*dal.GroupInfo, error) {
		return dal.GroupInfoDao.GetByIds(tc, []int64{1, 2})
	})

	if err != nil {
		fmt.Println(err)
	}
	j, _ := json.Marshal(gs)
	fmt.Println("queryByIdsUsingDao", string(j))
	fmt.Println(gs)
}

其他

分库分表

daog缺省支持分表,您需要为每个表指定分表函数,这需要设置TableMeta.ShardingFunc,具体需要在编译出的-ext.go文件的init函数中设置。 daog缺省支持分库,分库策略需要您实现DatasourceShardingPolicy接口,并在NewShardingDatasource是传入。ModInt64ShardingDatasourcePolicy是一个简单实现。GetDatasourceShardingKeyFromCtx函数实现了从context.Context中读取datasource sharding key的能力。

日志输出

通过DbConf.LogSQL可以设置该数据源是否需要输出执行的sql及参数,可以为数据源指定,每个一个TransContext执行时会继承这个配置,您也可以设置 TransContext.LogSQL属性为每个事务上下文设置,更细粒度的控制日志输出。

日志通过调用 daog.GLogger,它的数据类型是 SQLLogger 接口, 输出实现,缺省是调用标准库的log包,您也可以自行实现SQLLogger接口,并构建对象赋值给 GLogger 全局变量:

GetTraceIdFromContext函数可以从context.Context中读取traceId GetGoroutineIdFromContext 函数可以从 context.Context中读取创建TransContext的goroutine id

日期

golang的time.Time支持纳秒级别,但数据库支持秒级别即可,因此提供ttypes.NormalDate和ttypes.NormalDatetime来支持。 他们都内置了对json序列化的支持。序列化格式通过ttypes.DateFormat和ttypes.DatetimeFormat来设置,他们缺省是yyyy-MM-dd格式。

  • NormalDate.ToTimePointer 方法可以返回 NormalDate 包含的*time.Time
  • NormalDatetime.ToTimePointer 方法可以返回 NormalDatetime 包含的*time.Time

null字段值

golang sql包支持NullString, NullTime, NullFloat64, Nullxxx类型,但这些类型没有实现json序列化、反序列化接口。daog仅仅支持NullString和NullTime,其他的不支持, 这是因为实际的业务中,大部分情况要求字段是非空,尤其是数字数据类型。daog封装了NilableDate、NilableDatetime、NilableString三种类型,并提供一些函数用于简化开发,同时提供json序列化支持。

  • FromDatetime、FromDate、FromString函数用于把Time\string转换成Nilable对象;
  • NilableDate{},NilableDatetime{},NilableString{}表示null对象
  • NilableDate.ToTimePointer 方法可以返回 NilableDate 包含的*time.Time, 如果 NilableDate 包含nil,那返回nil
  • NilableDatetime.ToTimePointer 方法可以返回 NilableDatetime 包含的*time.Time, 如果 NilableDatetime 包含nil,那返回nil

for update

支持select for update,请使用Query*ForUpdate函数,或者 GetByIdForUpdate/GetByIdsForUpdate

Documentation

Overview

Package daog, 是轻量级的数据库访问组件,它并不能称之为orm组件,仅仅提供了一组函数用以实现常用的数据库访问功能。 它是高性能的,与原生的使用sql包函数相比,没有性能损耗,这是因为,它并没有使用反射技术,而是使用编译技术把create table sql语句编译成daog需要的go代码。 它目前仅支持mysql。

设计思路来源于java的[orm框架sampleGenericDao](https://github.com/tiandarwin/simpleGenericDao)和protobuf的编译思路。之所以选择编译 而没有使用反射,是因为基于编译的抽象没有性能损耗。

Index

Constants

View Source
const (

	// LikeStyleAll ,like "%value%"
	LikeStyleAll = 0
	// LikeStyleLeft ,like "%value"
	LikeStyleLeft = 1
	// LikeStyleRight ,like "value%"
	LikeStyleRight = 2
)

define "and","or" operand define like style, %xx%, %s,s%

View Source
const TableIdColumnName = "id"
View Source
const (
	TraceID = "trace-id"
)

Variables

View Source
var BeforeInsertCallback func(tableName string, ins any) error
View Source
var BeforeModifyCallback func(tableName string, modi Modifier, columns []string, values []any) error
View Source
var BeforeUpdateCallback func(tableName string, ins any) error

Functions

func AutoTrans added in v0.0.23

func AutoTrans(tCreatorFunc TcCreatorFunc, workFn func(tc *TransContext) error) error

AutoTrans 自动在事务内完成业务逻辑的包装函数,不返回业务返回值, 通过 tCreatorFunc 自动构建事务上下文, 然后执行 workFn 业务逻辑 如果不使用 AutoTrans 或者 AutoTransWithResult 你需要自行写一个defer 匿名函数用于最终提交或回滚事务,并且需要提前定义err变量,在业务执行过程中每个操作返回的err都需要赋值给err,而且每一步都需要判断err。如下:

var err error
tc,err := NewTransContext(...)
if err != nil {
     return err
}

defer func() {
    tc.CompleteWithPanic(err, recover())
}
err = run1(tc, ...)
if err != nil {
     return err
}
err = run1(tc, ...)
if err != nil {
     return err
}
return nil

func AutoTransWithResult added in v0.0.23

func AutoTransWithResult[T any](tCreatorFunc TcCreatorFunc, workFn func(tc *TransContext) (T, error)) (T, error)

AutoTransWithResult 自动在事务内完成业务逻辑的包装函数,需要业务返回值, 通过 tCreatorFunc 自动构建事务上下文, 然后执行 workFn 业务逻辑

func ChangeInt64ByFieldNameCallback added in v0.0.33

func ChangeInt64ByFieldNameCallback(valueMap map[string]any, fieldName string, extractor FieldPointExtractor) error

func ChangeModifierByFieldNameCallback added in v0.0.33

func ChangeModifierByFieldNameCallback(valueMap map[string]any, fieldName string, modifier Modifier, existField func(filedName string) bool) error

func ConvertToAnySlice

func ConvertToAnySlice[T any](data []T) []any

ConvertToAnySlice 把泛型的slice转换成 any类型的slice,在应用系统的上层往往是泛型slice,通过强类型校验来防止出错, 但在sql driver底层需要 []any进行参数传递,二者不能被编译器自动转换,所以需要该函数来转换

func Count added in v0.0.4

func Count[T any](tc *TransContext, m Matcher, meta *TableMeta[T]) (int64, error)

Count 表达 select count(*) 语义,其条件通过 Matcher 确定

func DeleteById

func DeleteById[T any](tc *TransContext, id int64, meta *TableMeta[T]) (int64, error)

DeleteById 根据主键id删除记录

参数: id 主键 , meta 表的元数据,由compile编译生成,比如 GroupInfo.GroupInfoMeta

返回值: 删除记录数,是否出错

func DeleteByIds

func DeleteByIds[T any](tc *TransContext, ids []int64, meta *TableMeta[T]) (int64, error)

DeleteByIds 根据主键id删除记录

参数: ids 一批主键 , meta 表的元数据,由compile编译生成,比如 GroupInfo.GroupInfoMeta

返回值: 删除记录数及是否出错

func DeleteByMatcher

func DeleteByMatcher[T any](tc *TransContext, matcher Matcher, meta *TableMeta[T]) (int64, error)

DeleteByMatcher 通过匹配条件删除数据,返回删除记录数及是否出错

func ExecRawSQL

func ExecRawSQL(tc *TransContext, sql string, args ...any) (int64, error)

ExecRawSQL 执行原生的sql

func GetAll added in v0.0.8

func GetAll[T any](tc *TransContext, meta *TableMeta[T], viewColumns ...string) ([]*T, error)

GetAll 查询表的所有数据 可变参数 viewColumns:

可以指定需要查询的表字段,可以指定多个或者不指定,如果不指定表示要查询所有的表字段

需要注意的是,表字段指的是数据库表的列名,不是描述表的struct里的属性名

compile生成的文件中会有表字段的常量,比如 GroupInfo.go 文件中的 GroupInfoFields.Id, 直接使用它,避免手动写字符串

func GetAllWithViewObj added in v0.0.30

func GetAllWithViewObj[T any](tc *TransContext, meta *TableMeta[T], view *View) ([]*T, error)

GetAllWithViewObj 查询表的所有数据 view:视图

compile生成的文件中会有表字段的常量,比如 GroupInfo.go 文件中的 GroupInfoFields.Id, 直接使用它,避免手动写字符串

func GetById

func GetById[T any](tc *TransContext, id int64, meta *TableMeta[T], viewColumns ...string) (*T, error)

GetById 根据指定的主键返回单条数据 可变参数 viewColumns:

可以指定需要查询的表字段,可以指定多个或者不指定,如果不指定表示要查询所有的表字段

需要注意的是,表字段指的是数据库表的列名,不是描述表的struct里的属性名

compile生成的文件中会有表字段的常量,比如 GroupInfo.go 文件中的 GroupInfoFields.Id, 直接使用它,避免手动写字符串

func GetByIdForUpdate added in v0.0.29

func GetByIdForUpdate[T any](tc *TransContext, id int64, meta *TableMeta[T], skipLocked bool, viewColumns ...string) (*T, error)

GetByIdForUpdate 类似 GetById, 只是支持 for update skipLocked, true 需要 SKIP LOCKED

func GetByIdWithViewObj added in v0.0.30

func GetByIdWithViewObj[T any](tc *TransContext, id int64, meta *TableMeta[T], view *View) (*T, error)

GetByIdWithViewObj 根据指定的主键返回单条数据 view: 表示视图

compile生成的文件中会有表字段的常量,比如 GroupInfo.go 文件中的 GroupInfoFields.Id, 直接使用它,避免手动写字符串

func GetByIds

func GetByIds[T any](tc *TransContext, ids []int64, meta *TableMeta[T], viewColumns ...string) ([]*T, error)

GetByIds 根据主键数组返回多条数据 可变参数 viewColumns:

可以指定需要查询的表字段,可以指定多个或者不指定,如果不指定表示要查询所有的表字段

需要注意的是,表字段指的是数据库表的列名,不是描述表的struct里的属性名

compile生成的文件中会有表字段的常量,比如 GroupInfo.go 文件中的 GroupInfoFields.Id, 直接使用它,避免手动写字符串

func GetByIdsForUpdate added in v0.0.29

func GetByIdsForUpdate[T any](tc *TransContext, ids []int64, meta *TableMeta[T], skipLocked bool, viewColumns ...string) ([]*T, error)

GetByIdsForUpdate 类似 GetByIds, 只是支持 for update skipLocked, true 需要 SKIP LOCKED

func GetByIdsWithViewObj added in v0.0.30

func GetByIdsWithViewObj[T any](tc *TransContext, ids []int64, meta *TableMeta[T], view *View) ([]*T, error)

GetByIdsWithViewObj 根据主键数组返回多条数据 view:查询视图

compile生成的文件中会有表字段的常量,比如 GroupInfo.go 文件中的 GroupInfoFields.Id, 直接使用它,避免手动写字符串

func GetGoroutineIdFromContext added in v0.0.14

func GetGoroutineIdFromContext(ctx context.Context) uint64

GetGoroutineIdFromContext 从 context.Context 中读取启动事务的 goroutine id

func GetTableName

func GetTableName[T any](ctx context.Context, meta *TableMeta[T]) string

GetTableName 根据meta及上下文中的信息来确定表名称,这应用于分表的场景,记住这需要支持表shard的事务上下文

func GetTraceIdFromContext

func GetTraceIdFromContext(ctx context.Context) string

GetTraceIdFromContext 从 context.Context 中读取trace id

func Insert

func Insert[T any](tc *TransContext, ins *T, meta *TableMeta[T]) (int64, error)

Insert 插入一条数据到表中,如果表有自增id,那么生成的id赋值到ins对象中

参数: ins 表实体对象,对应表的struct由 compile生成,比如 GroupInfo, meta 表的元数据,由compile编译生成,比如 GroupInfo.GroupInfoMeta

返回值: 插入的记录数,是否出错

func QueryListMatcher

func QueryListMatcher[T any](tc *TransContext, m Matcher, meta *TableMeta[T], orders ...*Order) ([]*T, error)

QueryListMatcher 根据查询条件 Matcher 返回多条数据, 通过与 Matcher 有关的相关函数来构建查询条件 orders 可变参数:

可以传入一个、多个或者零个排序条件

每个条件可以指定排序表字段名及是否是升序要求

func QueryListMatcherByBatchHandle added in v0.0.4

func QueryListMatcherByBatchHandle[T any](tc *TransContext, m Matcher, meta *TableMeta[T], totalLimit int, batchSize int, handler BatchHandler[T], orders ...*Order) error

QueryListMatcherByBatchHandle 读取数据并且分批处理数据,当读取的数据量巨大时非常有用,如果数据都读入内存,容易打爆内存,分批量处理就非常有用 batchSize 每批处理数据的最大容量,必须大于0,但不要设置太大,当设置为1时,退化成每条处理 handler 用于处理每批数据的函数 查询数据最大上限数, 0 表示无上限

func QueryListMatcherForUpdate added in v0.0.29

func QueryListMatcherForUpdate[T any](tc *TransContext, m Matcher, meta *TableMeta[T], skipLocked bool, orders ...*Order) ([]*T, error)

QueryListMatcherForUpdate 与 QueryListMatcher 类似,只是支持 for update skipLocked, true 需要 SKIP LOCKED

func QueryListMatcherWithViewColumns added in v0.0.29

func QueryListMatcherWithViewColumns[T any](tc *TransContext, m Matcher, meta *TableMeta[T], viewColumns []string, orders ...*Order) ([]*T, error)

QueryListMatcherWithViewColumns 根据查询条件 Matcher 返回多条数据,每条数据可以是一个视图, 通过与 Matcher 有关的相关函数来构建查询条件, viewColumns 指定需要查询的表字段名,表示一个视图 orders 可变参数:

可以传入一个、多个或者零个排序条件

每个条件可以指定排序表字段名及是否是升序要求

func QueryListMatcherWithViewColumnsByBatchHandle added in v0.0.4

func QueryListMatcherWithViewColumnsByBatchHandle[T any](tc *TransContext, m Matcher, meta *TableMeta[T], viewColumns []string, totalLimit int, batchSize int, handler BatchHandler[T], orders ...*Order) error

QueryListMatcherWithViewColumnsByBatchHandle 与 QueryListMatcherByBatchHandle 类似,适合分批读取少量数据并回调 BatchHandler 进行处理,与 QueryListMatcherByBatchHandle 稍有不同的是它提供 viewColumns 参数,可以只查询 viewColumns 指定的表字段 viewColumns 指定需要查询的表字段名,表示一个视图, 可以传入 nil, 表示读取所有字段

func QueryListMatcherWithViewColumnsForUpdate added in v0.0.29

func QueryListMatcherWithViewColumnsForUpdate[T any](tc *TransContext, m Matcher, meta *TableMeta[T], viewColumns []string, skipLocked bool, orders ...*Order) ([]*T, error)

QueryListMatcherWithViewColumnsForUpdate 与 QueryListMatcherWithViewColumns 类似,只是支持 for update skipLocked, true 需要 SKIP LOCKED

func QueryListMatcherWithViewObj added in v0.0.30

func QueryListMatcherWithViewObj[T any](tc *TransContext, m Matcher, meta *TableMeta[T], view *View, orders ...*Order) ([]*T, error)

QueryListMatcherWithViewObj 根据查询条件 Matcher 返回多条数据,每条数据可以是一个视图, 通过与 Matcher 有关的相关函数来构建查询条件, view 指定需要查询的视图 orders 可变参数:

可以传入一个、多个或者零个排序条件

每个条件可以指定排序表字段名及是否是升序要求

func QueryOneMatcher

func QueryOneMatcher[T any](tc *TransContext, m Matcher, meta *TableMeta[T], viewColumns ...string) (*T, error)

QueryOneMatcher 通过 Matcher 条件来查询,但只返回单条数据 viewColumns 可以指定需要查询的表字段,可以指定多个或者不指定,如果不指定表示要查询所有的表字段

func QueryOneMatcherForUpdate added in v0.0.29

func QueryOneMatcherForUpdate[T any](tc *TransContext, m Matcher, meta *TableMeta[T], skipLocked bool, viewColumns ...string) (*T, error)

QueryOneMatcherForUpdate 与 QueryOneMatcher, 只是支持 for update skipLocked, true 需要 SKIP LOCKED

func QueryOneMatcherWithViewObj added in v0.0.30

func QueryOneMatcherWithViewObj[T any](tc *TransContext, m Matcher, meta *TableMeta[T], view *View) (*T, error)

QueryOneMatcherWithViewObj 通过 Matcher 条件来查询,但只返回单条数据 view 视图

func QueryPageListMatcher added in v0.0.4

func QueryPageListMatcher[T any](tc *TransContext, m Matcher, meta *TableMeta[T], pager *Pager, orders ...*Order) ([]*T, error)

QueryPageListMatcher 根据查询条件 Matcher 及 Pager 返回一页数据, 通过与 Matcher 有关的相关函数来构建查询条件, 根据 Pager 相关函数来构建分页条件 orders 可变参数:

可以传入一个、多个或者零个排序条件

每个条件可以指定排序表字段名及是否是升序要求

pager 参数,可以为nil,如果为nil,不分页

func QueryPageListMatcherForUpdate added in v0.0.29

func QueryPageListMatcherForUpdate[T any](tc *TransContext, m Matcher, meta *TableMeta[T], pager *Pager, skipLocked bool, orders ...*Order) ([]*T, error)

QueryPageListMatcherForUpdate 与 QueryPageListMatcher 类似, 只是支持 for update skipLocked, true 需要 SKIP LOCKED

func QueryPageListMatcherWithViewColumns added in v0.0.4

func QueryPageListMatcherWithViewColumns[T any](tc *TransContext, m Matcher, meta *TableMeta[T], viewColumns []string, pager *Pager, orders ...*Order) ([]*T, error)

QueryPageListMatcherWithViewColumns 根据查询条件 Matcher 及 Pager 返回一页数据, 通过与 Matcher 有关的相关函数来构建查询条件, 根据 Pager 相关函数来构建分页条件, viewColumns 指定需要查询的表字段名,表示一个视图 orders 可变参数:

可以传入一个、多个或者零个排序条件

每个条件可以指定排序表字段名及是否是升序要求

pager 参数,可以为nil,如果为nil,不分页

viewColumns 指定需要查询的表字段名,表示一个视图, 可以传入 nil, 表示读取所有字段

func QueryPageListMatcherWithViewColumnsForUpdate added in v0.0.29

func QueryPageListMatcherWithViewColumnsForUpdate[T any](tc *TransContext, m Matcher, meta *TableMeta[T], viewColumns []string, pager *Pager, skipLocked bool, orders ...*Order) ([]*T, error)

QueryPageListMatcherWithViewColumnsForUpdate 与 QueryPageListMatcherWithViewColumns 类似, 只是支持 for update skipLocked, true 需要 SKIP LOCKED

func QueryPageListMatcherWithViewObj added in v0.0.30

func QueryPageListMatcherWithViewObj[T any](tc *TransContext, m Matcher, meta *TableMeta[T], view *View, pager *Pager, orders ...*Order) ([]*T, error)

QueryPageListMatcherWithViewObj 根据查询条件 Matcher 及 Pager 返回一页数据, 通过与 Matcher 有关的相关函数来构建查询条件, 根据 Pager 相关函数来构建分页条件, view 指定需要查询的视图 orders 可变参数:

可以传入一个、多个或者零个排序条件

每个条件可以指定排序表字段名及是否是升序要求

pager 参数,可以为nil,如果为nil,不分页

viewColumns 指定需要查询的表字段名,表示一个视图, 可以传入 nil, 表示读取所有字段

func QueryRawSQL added in v0.0.2

func QueryRawSQL[T any](tc *TransContext, extract ExtractScanFieldPoints[T], sql string, args ...any) ([]*T, error)

QueryRawSQL 执行原生select sql语句,返回行数据数组,行数据使用T struct描述 mapper, 它T的各个field指针提取出来并按照顺序生成一个slice,用于Row.Scan方法,把sql字段映射到T对象的各个Field上 sql 必须是含有 ? 占位符的sql, args 是对应每个 ? 的实参

func QueryRawSQLByBatchHandle added in v0.0.4

func QueryRawSQLByBatchHandle[T any](tc *TransContext, batchSize int, handler BatchHandler[T], extract ExtractScanFieldPoints[T], sql string, args ...any) error

QueryRawSQLByBatchHandle 与 QueryRawSQL 和 QueryListMatcherByBatchHandle 结合体,执行原生的sql语句,但通过回调 BatchHandler 进行分批业务处理 batchSize 每批处理数据的最大容量,必须大于0,但不要设置太大,当设置为1时,退化成每条处理 handler 用于处理每批数据的函数

func Update

func Update[T any](tc *TransContext, ins *T, meta *TableMeta[T]) (int64, error)

Update 更新一条数据,把 *T类型的 ins 更新到数据,ins中的主键必须被设置 meta 表的元数据,由compile编译生成,比如 GroupInfo.GroupInfoMeta 返回值是 更新的数据的条数,是0或者1

func UpdateById

func UpdateById[T any](tc *TransContext, modifier Modifier, id int64, meta *TableMeta[T]) (int64, error)

UpdateById 根据主键修改一条记录,需要修改的字段值通过 Modifier 指定

func UpdateByIds

func UpdateByIds[T any](tc *TransContext, modifier Modifier, ids []int64, meta *TableMeta[T]) (int64, error)

UpdateByIds 根据多个主键修改多条记录,需要修改的字段值通过 Modifier 指定,表达 update table set a=?,b=? where id in(xx,xx)的语义

func UpdateByModifier

func UpdateByModifier[T any](tc *TransContext, modifier Modifier, matcher Matcher, meta *TableMeta[T]) (int64, error)

UpdateByModifier 根据Matcher条件修改多条记录,需要修改的字段值通过 Modifier 指定,表达 update table set a=?,b=? where uid=? and status=0 的类似语义

func UpdateList

func UpdateList[T any](tc *TransContext, insList []*T, meta *TableMeta[T]) (int64, error)

UpdateList 更新多条数据,把多个 *T类型的 ins 更新到数据,每个ins中的主键必须被设置 meta 表的元数据,由compile编译生成,比如 GroupInfo.GroupInfoMeta 返回值是 更新的数据的条数,是0或者1 注意: 当 tc 的事务类型是 txrequest.RequestNone 时,如果某一个 ins 更新失败,会立即返回错误,但该 ins之前的更新都会成功,此时的两个返回值都不是0值

func WrapTrans added in v0.0.9

func WrapTrans(tc *TransContext, workFn func(tc *TransContext) error) error

WrapTrans 在一个事务内执行所有的业务操作并最终根据err或者panic来判断是否提交事务。 Deprecated, 后面会被取消掉,请使用 AutoTrans 如果不使用 WrapTrans 或者 WrapTransWithResult 你需要自行写一个defer 匿名函数用于最终提交或回滚事务,并且需要提前定义err变量,在业务执行过程中每个操作返回的err都需要赋值给err,而且每一步都需要判断err。如下:

var err error
tc,err := NewTransContext(...)
if err != nil {
     return err
}

defer func() {
    tc.CompleteWithPanic(err, recover())
}
err = run1(tc, ...)
if err != nil {
     return err
}
err = run1(tc, ...)
if err != nil {
     return err
}
return nil

func WrapTransWithResult added in v0.0.9

func WrapTransWithResult[T any](tc *TransContext, workFn func(tc *TransContext) (T, error)) (T, error)

WrapTransWithResult 与WrapTrans类似,不同的是业务处理函数可以有返回值 Deprecated, 后面会取消掉,请使用 AutoTransWithResult

Types

type AddNewModifyFieldBeforeUpdateInterceptor added in v0.0.33

type AddNewModifyFieldBeforeUpdateInterceptor func(valueMap map[string]any, modifier Modifier, existField func(filedName string) bool) error
var AddNewModifyFieldBeforeUpdate AddNewModifyFieldBeforeUpdateInterceptor

type AfterTransBeginInterceptor added in v0.0.33

type AfterTransBeginInterceptor func(tx *TransContext) error
var TransBegunInterceptor AfterTransBeginInterceptor

type BatchHandler added in v0.0.4

type BatchHandler[T any] func(batch []*T) error

BatchHandler 处理一批从表中读取的数据的回调函数 被 QueryListMatcherByBatchHandle 或者 QueryListMatcherWithViewColumnsByBatchHandle 回调使用, 一般用于从数据库读取大量数据的场景, 如果大量数据读入内存会打爆内存,一批批的处理少量数据可以有效的降低内存

type ChangeFieldValueBeforeWriteInterceptor added in v0.0.33

type ChangeFieldValueBeforeWriteInterceptor func(valueMap map[string]any, extractor FieldPointExtractor) error
var ChangeFieldOfInsBeforeWrite ChangeFieldValueBeforeWriteInterceptor

type Datasource

type Datasource interface {

	// Shutdown 关闭数据源
	Shutdown()
	// IsLogSQL 本数据源是否需要输出执行的sql到日志
	IsLogSQL() bool
	// contains filtered or unexported methods
}

Datasource 描述一个数据源,确切的说是一个数据源分片,它对应一个mysql database

func NewDatasource

func NewDatasource(conf *DbConf) (Datasource, error)

NewDatasource 按照配置创建单个数据源对象

func NewShardingDatasource

func NewShardingDatasource(confs []*DbConf, policy DatasourceShardingPolicy) (Datasource, error)

NewShardingDatasource 创建多分片数据源,创建好的数据源是复合数据源,内含confs参数指定的多个数据源,也包含一个分片策略, 使用 NewShardingDatasource 数据源时要求使用 NewTransContextWithSharding 来创建事务上下文

type DatasourceShardingPolicy

type DatasourceShardingPolicy interface {
	// Shard 根据分片key和分片总数来路由分片数据源
	Shard(shardKey any, count int) (int, error)
}

DatasourceShardingPolicy 数据源分片策略

type DbConf

type DbConf struct {
	// 数据库url
	DbUrl string
	// 最大连接数
	Size int
	// 连接的最大生命周期,单位是秒
	Life int
	// 最大空闲连接数
	IdleCons int
	// 最大空闲时间,单位是秒
	IdleTime int
	// 该在该数据源上执行sql是是否需要把待执行的sql输出到日志
	LogSQL bool
	// 读取连接超时时间,单位是秒
	GetConnTimeout int64
}

DbConf 数据源配置, 包括数据库url和连接池相关配置,特别注意,它支持按数据源在日志中输出执行的sql

type ExtractScanFieldPoints added in v0.0.3

type ExtractScanFieldPoints[T any] func(ins *T) []any

ExtractScanFieldPoints 从指定的 *T 类型的对象中抽取出所需要的 field的指针,它是一个回调函数,用于 QueryRawSQL 或者 QueryRawSQLByBatchHandle 函数, 其目的是把从数据库读取的一行数据填充到指定 *T 对象中,这对于执行一个原生的 sql 非常有用。

type FieldPointExtractor added in v0.0.33

type FieldPointExtractor interface {
	// Extract 返回值内存储一个指针,当给定的fieldName不存在时,返回nil
	Extract(fieldName string) any
}

type Matcher

type Matcher interface {
	SQLCond

	// Add 这个方法是个冗余方法,其实可以直接使用AddCond, 因为Matcher继承自SQLCond,冗余这个方法仅仅是让使用者更好的理解
	Add(matcher Matcher) Matcher

	// AddCond 加入一个新的到条件
	AddCond(cond SQLCond) Matcher

	// Eq 快速生成一个等于语义的条件,比如 id = 100
	// column 是数据库表的字段名,value是条件值
	Eq(column string, value any) Matcher

	// Ne 快速生成一个 not equals 条件语义, Eq 的反向
	Ne(column string, value any) Matcher

	// Lt 快速生成一个 less than 条件语义
	Lt(column string, value any) Matcher

	// Lte 快速生成一个 less than or equals 条件语义
	Lte(column string, value any) Matcher

	// Gt 快速生成一个greater than 条件语义
	Gt(column string, value any) Matcher

	// Gte 快速生成一个 greater than or equals 条件语义
	Gte(column string, value any) Matcher

	// In 快速生成in 条件语义,比如 xx in(?,?,...)
	In(column string, values []any) Matcher

	// NotIn 快速生成 not in 语义,比如 xx not in(?,?,...)
	NotIn(column string, values []any) Matcher

	// Like 快速生成 like 条件语义, 参数 likeStyle对应 枚举值: LikeStyleAll/ LikeStyleLeft / LikeStyleRight
	Like(column string, value string, likeStyle int) Matcher

	// Null 快速生成是否为空的条件语义,比如 name is null,  参数not表示是否为not null, 如果为true, 则生成条件 name is not null
	Null(column string, not bool) Matcher

	// Between 快速生成between 语义, start 和end可以有一个为 nil, 如果 start = nil,则退化成 column <= end, 如果 end = nil,则退化成 column >= end
	// 两个都不为nil,生成标准的between语义
	Between(column string, start any, end any) Matcher

	// AddScalar 增加一个标量条件,即增加一个条件字符串,比如 "id = 100", 或者 "name = 'Joe'",
	// 注意 尽量不要使用这个方法,因为它容易引起sql注入,如果你需要使用这个方法,你一定要使用转义来防止sql注入
	AddScalar(cond string) Matcher

	// BitwiseAnd , 位与, a & 1 = 1
	// 注意 mask, target 类型必须相同,支持 int int8 int16 int32 int64
	BitwiseAnd(column string, mask, target any) Matcher
}

Matcher sql where条件的构建器,用以构造以 and 或者 or 连接的各种条件, 最后拼接生成一个可用的、包含?占位符的where条件,并且收集所有对应?的参数数组

func NewAndMatcher

func NewAndMatcher() Matcher

NewAndMatcher 构建一个以 and 连接的匹配条件构建器

func NewMatcher

func NewMatcher() Matcher

NewMatcher 构建一个以 and 连接的匹配条件构建器

func NewOrMatcher

func NewOrMatcher() Matcher

NewOrMatcher 构建一个以 or 连接的匹配条件构建器

type ModInt64ShardingDatasourcePolicy

type ModInt64ShardingDatasourcePolicy int64

ModInt64ShardingDatasourcePolicy 分片key是int64直接对分片总数取模路由策略,这是最简单的方式

func (ModInt64ShardingDatasourcePolicy) Shard

func (h ModInt64ShardingDatasourcePolicy) Shard(shardKey any, count int) (int, error)

type Modifier

type Modifier interface {
	// Add 增加一个字段的修改,比如 id = 100
	Add(column string, value any) Modifier
	SelfAdd(column string, value any) Modifier
	SelfMinus(column string, value any) Modifier
	// contains filtered or unexported methods
}

Modifier 描述 update 语义中set cause的生成,通过 Modifier 来避免自己拼接sql片段,降低出错概率, 最终生成 update tab set xx=?,bb=? 的 sql 片段

func NewModifier added in v0.0.6

func NewModifier() Modifier

NewModifier 创建 Modifier 对象

type Order added in v0.0.4

type Order struct {
	ColumnName string
	Desc       bool
}

Order 描述sql中的单个 order 条件

func NewDescOrder added in v0.0.4

func NewDescOrder(columnName string) *Order

func NewOrder added in v0.0.4

func NewOrder(columnName string) *Order

type OrdersBuilder added in v0.0.8

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

OrdersBuilder 构建order by 条件工具

func NewOrdersBuilder added in v0.0.8

func NewOrdersBuilder() *OrdersBuilder

NewOrdersBuilder 构建 OrdersBuilder对象

func (*OrdersBuilder) Build added in v0.0.8

func (orders *OrdersBuilder) Build() []*Order

Build 构建出最终的 order by sql 片段

func (*OrdersBuilder) NewDescOrder added in v0.0.8

func (orders *OrdersBuilder) NewDescOrder(columnName string) *OrdersBuilder

NewDescOrder 增加一个降序的条件

func (*OrdersBuilder) NewOrder added in v0.0.8

func (orders *OrdersBuilder) NewOrder(columnName string) *OrdersBuilder

NewOrder 增加一个升序的条件

type Pager added in v0.0.4

type Pager struct {
	PageSize   int
	PageNumber int
}

Pager 分页参数结构,PageSize 每一页的大小,PageNumber 页码,从1算起

func NewPager added in v0.0.4

func NewPager(pageSize int, pageNumber int) *Pager

type QuickDao added in v0.0.3

type QuickDao[T any] interface {
	// GetAll 封装 GetAll 函数
	GetAll(tc *TransContext, viewColumns ...string) ([]*T, error)

	// GetAllWithViewObj 封装 GetAllWithViewObj 函数
	GetAllWithViewObj(tc *TransContext, view *View) ([]*T, error)
	// GetById 封装 GetById 函数
	GetById(tc *TransContext, id int64, viewColumns ...string) (*T, error)

	// GetByIdWithViewObj 封装 GetByIdWithViewObj 函数
	GetByIdWithViewObj(tc *TransContext, id int64, view *View) (*T, error)

	// GetByIdForUpdate 封装 GetByIdForUpdate 函数
	GetByIdForUpdate(tc *TransContext, id int64, skipLocked bool, viewColumns ...string) (*T, error)

	// GetByIds 封装 GetByIds 函数
	GetByIds(tc *TransContext, ids []int64, viewColumns ...string) ([]*T, error)

	// GetByIdsWithViewObj 封装 GetByIdsWithViewObj 函数
	GetByIdsWithViewObj(tc *TransContext, ids []int64, view *View) ([]*T, error)

	// GetByIdsForUpdate 封装 GetByIdsForUpdate 函数
	GetByIdsForUpdate(tc *TransContext, ids []int64, skipLocked bool, viewColumns ...string) ([]*T, error)
	// QueryListMatcher 封装 QueryListMatcher 函数
	QueryListMatcher(tc *TransContext, m Matcher, orders ...*Order) ([]*T, error)
	// QueryListMatcherWithViewColumns 封装 QueryListMatcherWithViewColumns 函数
	QueryListMatcherWithViewColumns(tc *TransContext, m Matcher, viewColumns []string, orders ...*Order) ([]*T, error)
	// QueryListMatcherWithViewObj 封装 QueryListMatcherWithViewObj 函数
	QueryListMatcherWithViewObj(tc *TransContext, m Matcher, view *View, orders ...*Order) ([]*T, error)

	// QueryListMatcherWithViewColumnsForUpdate 封装 QueryListMatcherWithViewColumnsForUpdate 函数
	QueryListMatcherWithViewColumnsForUpdate(tc *TransContext, m Matcher, viewColumns []string, skipLocked bool, orders ...*Order) ([]*T, error)
	// QueryPageListMatcher 封装 QueryPageListMatcher 函数
	QueryPageListMatcher(tc *TransContext, m Matcher, pager *Pager, orders ...*Order) ([]*T, error)
	// QueryPageListMatcherForUpdate 封装 QueryPageListMatcherForUpdate 函数
	QueryPageListMatcherForUpdate(tc *TransContext, m Matcher, pager *Pager, skipLocked bool, orders ...*Order) ([]*T, error)
	// QueryListMatcherForUpdate 封装 QueryListMatcherForUpdate 函数
	QueryListMatcherForUpdate(tc *TransContext, m Matcher, skipLocked bool, orders ...*Order) ([]*T, error)
	// QueryPageListMatcherWithViewColumns 封装 QueryPageListMatcherWithViewColumns 函数
	QueryPageListMatcherWithViewColumns(tc *TransContext, m Matcher, viewColumns []string, pager *Pager, orders ...*Order) ([]*T, error)

	// QueryPageListMatcherWithViewObj 封装 QueryPageListMatcherWithViewObj 函数
	QueryPageListMatcherWithViewObj(tc *TransContext, m Matcher, view *View, pager *Pager, orders ...*Order) ([]*T, error)

	// QueryPageListMatcherWithViewColumnsForUpdate 封装 QueryPageListMatcherWithViewColumnsForUpdate 函数
	QueryPageListMatcherWithViewColumnsForUpdate(tc *TransContext, m Matcher, viewColumns []string, pager *Pager, skipLocked bool, orders ...*Order) ([]*T, error)
	// QueryListMatcherByBatchHandle 封装 QueryListMatcherByBatchHandle 函数
	QueryListMatcherByBatchHandle(tc *TransContext, m Matcher, totalLimit int, batchSize int, handler BatchHandler[T], orders ...*Order) error
	// QueryListMatcherWithViewColumnsByBatchHandle 封装 QueryListMatcherWithViewColumnsByBatchHandle 函数
	QueryListMatcherWithViewColumnsByBatchHandle(tc *TransContext, m Matcher, viewColumns []string, totalLimit int, batchSize int, handler BatchHandler[T], orders ...*Order) error
	// QueryOneMatcher 封装 QueryOneMatcher 函数
	QueryOneMatcher(tc *TransContext, m Matcher, viewColumns ...string) (*T, error)

	// QueryOneMatcherWithViewObj 封装 QueryOneMatcherWithViewObj 函数
	QueryOneMatcherWithViewObj(tc *TransContext, m Matcher, view *View) (*T, error)

	// QueryOneMatcherForUpdate 封装 QueryOneMatcherForUpdate 函数
	QueryOneMatcherForUpdate(tc *TransContext, m Matcher, skipLocked bool, viewColumns ...string) (*T, error)
	// QueryRawSQL 封装 QueryRawSQL 函数
	QueryRawSQL(tc *TransContext, extract ExtractScanFieldPoints[T], sql string, args ...any) ([]*T, error)
	// QueryRawSQLByBatchHandle 封装 QueryRawSQLByBatchHandle 函数
	QueryRawSQLByBatchHandle(tc *TransContext, batchSize int, handler BatchHandler[T], extract ExtractScanFieldPoints[T], sql string, args ...any) error

	// Count 封装 Count 函数
	Count(tc *TransContext, m Matcher) (int64, error)

	// Insert 封装 Insert 函数
	Insert(tc *TransContext, ins *T) (int64, error)

	// Update 封装 Update 函数
	Update(tc *TransContext, ins *T) (int64, error)
	// UpdateList 封装 UpdateList 函数
	UpdateList(tc *TransContext, insList []*T) (int64, error)
	// UpdateById 封装 UpdateById 函数
	UpdateById(tc *TransContext, modifier Modifier, id int64) (int64, error)
	// UpdateByIds 封装 UpdateByIds 函数
	UpdateByIds(tc *TransContext, modifier Modifier, ids []int64) (int64, error)
	// UpdateByModifier 封装 UpdateByModifier 函数
	UpdateByModifier(tc *TransContext, modifier Modifier, matcher Matcher) (int64, error)
	// ExecRawSQL 封装 ExecRawSQL 函数
	ExecRawSQL(tc *TransContext, sql string, args ...any) (int64, error)

	// DeleteById 封装 DeleteById 函数
	DeleteById(tc *TransContext, id int64) (int64, error)
	// DeleteByIds 封装 DeleteByIds 函数
	DeleteByIds(tc *TransContext, ids []int64) (int64, error)
	// DeleteByMatcher 封装 GetById 函数
	DeleteByMatcher(tc *TransContext, matcher Matcher) (int64, error)
}

QuickDao 类似于java的Dao接口,用于仅仅访问一张表。 针对每一张表生成一个实现 QuickDao 的struct的实例,使用这个实例来操作这张表。相对于直接调用诸如 GetAll 、 GetById 等函数可以少传入 TableMeta 对象,并且让代码看起来更面向对象。 针对每一张表的 QuickDao 不用自行实现, compile 会自动生成,比如 GroupInfo.go文件中GroupInfoDao

func NewBaseQuickDao added in v0.0.3

func NewBaseQuickDao[T any](meta *TableMeta[T]) QuickDao[T]

type SQLCond

type SQLCond interface {
	// ToSQL 生成包含?占位符的sql,并返回对应的参数数组
	// 输入参数 args是已经收集到的参数
	ToSQL(args []any) (string, []any, error)
}

SQLCond 抽象描述一个sql的条件,可以是 单个字段的条件,比如 name=?, 也可以是通过连接操作符(and/or)连接的多个条件。 每一个条件以 [字段 操作符 值占位符] 的方式组成,比如 id = ?,生成条件时需要传入每个占位符对应一个参数值 也可以直接给一个标量条件,没有参数,比如 status = 0

type SQLLogger added in v0.0.16

type SQLLogger interface {
	// Error 输出错误日志
	Error(ctx context.Context, err error)
	// Info 输出 Info级别日志
	Info(ctx context.Context, content string)
	// ExecSQLBefore 在 sql 执行前输出它,这需要你在 构建数据源时指定的 DbConf.LogSQL = true
	ExecSQLBefore(ctx context.Context, sql string, argsJson []byte, sqlMd5 string)
	// ExecSQLAfter  在 sql 执行后输出它,这需要你在 构建数据源时指定的 DbConf.LogSQL = true
	ExecSQLAfter(ctx context.Context, sqlMd5 string, cost int64)
	// SimpleLogError 输出err,应用于你还没有构建 TransContext 前,此时 context.Context 还没有被初始化,对应err直接输出即可
	SimpleLogError(err error)
}

SQLLogger 封装log类似与java slf4j的功能 输出日志时你可以调用 GetTraceIdFromContext 从 context.Context 读取到traceId,并在输出日志时输出它,当然,前题是你在 NewTransContext 时指定了traceId 你也可以调用 GetGoroutineIdFromContext 读取到调用 NewTransContext 的 goroutine 的 goroutine id, 并在日志中输出它

var GLogger SQLLogger = &defaultLogger{}

GLogger 全局的日志接口对象, 您可以实现自己 SQLLogger 对象并赋值给 GLogger, 则可以自行输出日志

type TableMeta

type TableMeta[T any] struct {
	// 通过表的字段名称获取表实体对象中对应的field的值,或者该field的指针,取值一般用于insert or update,
	// 取指针一般用于从表中读取数据回填到表对象的field中,该函数会被compile自动生成
	LookupFieldFunc func(columnName string, ins *T, point bool) any
	// 在分表情况下,根据分表key生成分表名称的回调函数,该函数不能被compile自动生成,需要使用者在compile生成的xx-ext.go中设置
	ShardingFunc func(tableName string, shardingKey any) string
	Table        string
	Columns      []string
	// 自增长字段的名称,在insert时,表实体对象中对应的field会被自动填充
	AutoColumn   string
	StampColumns map[string]int
}

TableMeta daog中需要表的元数据,基于元数据来自动生成sql,把从数据库读取的数据分配给表的实体对象,TableMeta对应的实例会由compile工具生成。 TableMeta 需要知道表名,表的列名,自增长字段名称,以及需要提供一个函数LookupFieldFunc,该函数负责根据表的字段名称找到该名称对应的属性。

func (*TableMeta[T]) ExtractFieldValues

func (meta *TableMeta[T]) ExtractFieldValues(ins *T, point bool, exclude map[string]int) []any

ExtractFieldValues 从给定的T对象中抽取属性值,并返回,抽取的属性值可能是属性指针,也可能是属性的值, 通过exclude可以指定哪些列对应的属性被排除,exclude 中key是数据库表的字段名,不是表实体对象中的属性名

func (*TableMeta[T]) ExtractFieldValuesByColumns added in v0.0.4

func (meta *TableMeta[T]) ExtractFieldValuesByColumns(ins *T, point bool, columns []string) []any

ExtractFieldValuesByColumns 与ExtractFieldValues,但它仅仅抽取通过 columns 参数指定的数据表列所对应的属性

type TcCreatorFunc added in v0.0.23

type TcCreatorFunc func() (*TransContext, error)

TcCreatorFunc 创建事务上下文的回调函数

type TransContext

type TransContext struct {
	LogSQL  bool
	ExtInfo map[string]any
	// contains filtered or unexported fields
}

TransContext 事务的上下文,描述了数据事务,所有在该事务内执行的数据库操作都需要被提交或者回滚,保持原子性。在daog里要想执行数据库操作必须要确定TransContext, 他是数据操作的起点,一旦一个事务确定,对应的数据库连接确定,底层物理事务确定,同时它内部维护一个状态,用于记录事务的创建、提交/回滚, TransContext最终需要被调用 CompleteWithPanic 来进入终态,进入终态后,其生命周期即完成

func NewTransContext

func NewTransContext(datasource Datasource, txRequest txrequest.RequestStyle, traceId string) (*TransContext, error)

NewTransContext 创建一个单库单表的事务执行上下文

txRequest 指明了事务级别,事务级别参照 txrequest.RequestStyle

traceId 可以是nil,它代表一次业务请求,建议设置一个合理的值,它可以标记在执行的sql上,可以有效帮助排查问题

func NewTransContextWithSharding

func NewTransContextWithSharding(datasource Datasource, txRequest txrequest.RequestStyle, traceId string, tableShardingKeyValue any, dsShardingKeyValue any) (*TransContext, error)

NewTransContextWithSharding 创建支持分库分表的事务上下文

tableShardingKeyValue 指定分表key,可以为nil,表示没有分表, 分表策略需要设置表的 TableMeta.ShardingFunc ,因为表的 TableMeta 是在编译成生成,TableMeta.ShardingFunc 推荐在 对应生成的 xx-ext.go中设置,比如 GroupInfo-ext.go

dsShardingKeyValue 指定数据库分片key, 可以为nil, 表示没有分片

func (*TransContext) Complete

func (tc *TransContext) Complete(e error)

Complete 事务最终完成,可能是提交,也可能是会管,生命周期结束. e == nil, 提交事务,否则回滚 Deprecated, 后面会取消掉,请使用 CompleteWithPanic

func (*TransContext) CompleteWithPanic added in v0.0.13

func (tc *TransContext) CompleteWithPanic(e error, fetal any)

CompleteWithPanic 事务最终完成,可能是提交,也可能是会管,生命周期结束. fetal参数指明它是否遇到了一个panic,fetal是对应recover()返回的信息 如果 fetal != nil 则回滚 否则 如果 e == nil 则提交 否则 回滚

type View added in v0.0.30

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

View 定义查询的视图

func NewExcludeView added in v0.0.30

func NewExcludeView(excludeColumns []string) *View

NewExcludeView 创建view,指定的字段为视图要排除的字段

func NewView added in v0.0.30

func NewView(includeColumns []string) *View

NewView 创建view,指定的字段为视图包含的字段

Directories

Path Synopsis
dal
json command
Package ttypes 定义特殊类型支持,比如日期类型, golang的日期类型在转换成json时不能指定日期的格式,ttypes.NormalDate 可以按照 DateFormat指定的格式输出到json中或者fmt.Println.
Package ttypes 定义特殊类型支持,比如日期类型, golang的日期类型在转换成json时不能指定日期的格式,ttypes.NormalDate 可以按照 DateFormat指定的格式输出到json中或者fmt.Println.
Package txrequest, 定义了事务的级别,包括三个级别:
Package txrequest, 定义了事务的级别,包括三个级别:
Package utils, daog包使用的工具,现在只包含读取当前goroutine id的工具,未来可能会扩展
Package utils, daog包使用的工具,现在只包含读取当前goroutine id的工具,未来可能会扩展

Jump to

Keyboard shortcuts

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