Documentation
¶
Overview ¶
XOrm 拓展了 Beego 的 ORM 功能,同时实现了基于上下文的事务机制,提高了数据操作的效率。
功能特性
- 多源配置:通过解析首选项中的配置自动初始化数据库连接
- 数据模型:提供了面向对象的模型设计及常用的数据操作
- 事务操作:基于上下文的事务机制,支持缓存和并发控制
使用手册
1. 多源配置
配置说明:
- 配置键名:XOrm/Source/<数据库类型>/<数据库别名>
- 支持 MySQL、PostgreSQL、SQLite3 等(Beego ORM 支持的类型)
- 配置参数:
- Addr:数据源地址
- Pool:连接池大小
- Conn:最大连接数
配置示例:
{
"XOrm/Source/MySQL/Main": {
"Addr": "root:123456@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&loc=Local",
"Pool": 1,
"Conn": 1
},
"XOrm/Source/PostgreSQL/Log": {
"Addr": "postgres://user:pass@localhost:5432/dbname?sslmode=disable",
"Pool": 2,
"Conn": 10
},
"XOrm/Source/SQLite3/Type": {
"Addr": "file:data.db?cache=shared&mode=rwc",
"Pool": 1,
"Conn": 1
}
}
2. 数据模型
提供了面向对象的模型设计及常用的数据操作。
2.1 模型定义
// 定义用户模型
type User struct {
XOrm.Model[User] // 继承基础模型
ID int `orm:"column(id);pk"` // 主键字段
Name string `orm:"column(name)"` // 字符串字段
Age int `orm:"column(age)"` // 整型字段
}
// 实现必要的接口方法
func (u *User) AliasName() string {
return "mydb" // 数据库别名
}
func (u *User) TableName() string {
return "user" // 数据库表名
}
// 创建模型实例的工厂方法
func NewUser() *User {
return XObject.New[User]()
}
2.2 模型接口
模型接口定义了以下核心方法:
生命周期:
Ctor(obj any) // 构造初始化 OnEncode() // 编码前回调 OnDecode() // 解码后回调 OnQuery(action string, cond *orm.Condition) *orm.Condition // 查询时回调
基础信息:
AliasName() string // 数据库别名 TableName() string // 数据表名称 ModelUnique() string // 模型标识 DataUnique() string // 数据标识 DataValue(field string) any // 获取字段值
数据操作:
Read(cond ...*condition) bool // 读取数据 List(rets any, cond ...*condition) int // 列举数据 Write() int // 写入数据 Delete() int // 删除数据 Clear(cond ...*condition) int // 清除数据 Count(cond ...*condition) int // 统计数量 Max(column ...string) int // 获取最大值 Min(column ...string) int // 获取最小值
工具方法:
IsValid(value ...bool) bool // 检查/设置有效性 Clone() IModel // 深度拷贝 Json() string // JSON序列化 Equals(model IModel) bool // 对象比较 Matchs(cond ...*condition) bool // 条件匹配
2.3 模型注册
参数说明:
- cache:是否缓存,启用后支持全局缓存
- writable:是否可写,启用后支持修改数据
应用场景:
| 是否缓存 | 是否可写 | 应用场景 | |---------|----------|---------| | true | true | 适用于高频读取、写入且数据规模可控的模型,如用户信息等。 | | true | false | 适用于高频读取、无需写入的模型,如只读配置等。 | | false | true | 适用于高频写入,低频读取或者数据规模不可控的场景,如日志记录等。 |
注意:选择参数时除了考虑应用场景外,还需结合实际业务运行情况,如是否存在多个实例同时读写的情况。
示例代码:
// 用户模型:高频读取、写入且数据规模可控 // cache=true, writable=true XOrm.Meta(NewUser(), true, true) // 配置模型:高频读取、无需写入 // cache=true, writable=false XOrm.Meta(NewConfig(), true, false) // 日志模型:高频写入,低频读取或者数据规模不可控 // cache=false, writable=true XOrm.Meta(NewLog(), false, true)
2.4 条件查询
支持多种查询方式和复杂的条件组合。
创建条件:
// 1. 创建空条件
cond := XOrm.Cond()
// 2. 从现有条件创建
cond := XOrm.Cond(orm.NewCondition())
// 3. 从表达式创建(推荐)
cond := XOrm.Cond("age > {0} && name == {1}", 18, "test")
比较运算符:
// 大于/大于等于
cond := XOrm.Cond("age > {0}", 18) // age__gt
cond := XOrm.Cond("age >= {0}", 18) // age__gte
// 小于/小于等于
cond := XOrm.Cond("age < {0}", 18) // age__lt
cond := XOrm.Cond("age <= {0}", 18) // age__lte
// 等于/不等于
cond := XOrm.Cond("age == {0}", 18) // age__exact
cond := XOrm.Cond("age != {0}", 18) // age__ne
// 空值判断
cond := XOrm.Cond("age isnull {0}", true) // age__isnull
字符串匹配:
// 包含
cond := XOrm.Cond("name contains {0}", "test") // name__contains
// 前缀匹配
cond := XOrm.Cond("name startswith {0}", "test") // name__startswith
// 后缀匹配
cond := XOrm.Cond("name endswith {0}", "test") // name__endswith
逻辑组合:
// AND 组合
cond := XOrm.Cond("age > {0} && name == {1}", 18, "test")
// OR 组合
cond := XOrm.Cond("age < {0} || age > {1}", 18, 60)
// NOT 条件
cond := XOrm.Cond("!(age >= {0})", 30)
// 复杂组合
cond := XOrm.Cond("(age >= {0} && age <= {1}) || name == {2}", 18, 30, "test")
cond := XOrm.Cond("((age > {0} && name contains {1}) || status == {2}) && active == {3}", 18, "test", "active", true)
分页查询:
// 分页限定
cond := XOrm.Cond("age > {0} && limit = {1}", 18, 10)
// 分页偏移
cond := XOrm.Cond("age > {0} && offset = {1}", 18, 20)
// 组合使用
cond := XOrm.Cond("age > {0} && limit = {1} && offset = {2}", 18, 10, 20)
使用示例:
// 1. 简单查询
model := NewUser()
cond := XOrm.Cond("age > {0}", 18)
user := model.Read(cond)
if user.IsValid() {
fmt.Printf("Found user: %v\n", user.Name)
}
// 2. 复杂查询
model := NewUser()
var users []*User
cond := XOrm.Cond("(age >= {0} && age <= {1}) || name contains {2}", 18, 30, "test")
count := model.List(&users, cond)
fmt.Printf("Found %d users\n", count)
// 3. 分页查询
model := NewUser()
var users []*User
cond := XOrm.Cond("age > {0} && limit = {1} && offset = {2}", 18, 10, 20)
count := model.List(&users, cond)
fmt.Printf("Found %d users\n", count)
// 4. 统计查询
model := NewUser()
cond := XOrm.Cond("status == {0} && age > {1}", "active", 18)
count := model.Count(cond)
fmt.Printf("Found %d users\n", count)
注意事项: 1. 条件表达式中的参数使用 {n} 形式引用,n 从 0 开始 2. 参数数量必须与表达式中的占位符数量一致 3. 复杂条件建议使用括号明确优先级 4. 条件会被缓存以提高性能,相同的表达式只会解析一次 5. 支持所有 Beego ORM 的条件操作符
3. 事务操作
基于上下文的事务机制,支持缓存和并发控制。
3.1 基本操作
所有数据操作都需要在会话监听的上下文中进行,以确保缓存策略和事务控制的正确性:
// 开始 CRUD 监控。
sid := XOrm.Watch()
// 结束 CRUD 监控。
defer XOrm.Defer()
// 写入操作:写入数据到会话缓存和全局缓存。
user := NewUser()
user.Name = "test"
user.Age = 18
XOrm.Write(user)
// 读取操作:按优先级依次从会话缓存、全局缓存、远端数据库读取。
user := NewUser()
user.ID = 1
if XOrm.Read(user) { // 精确查找,检查缓存标记。
fmt.Printf("User: %v\n", user.Name)
}
// 条件读取:支持模糊查找和条件匹配。
cond := XOrm.Cond("age > {0}", 18)
if XOrm.Read(user, cond) { // 模糊查找,可能触发远端读取。
fmt.Printf("User: %v\n", user.Name)
}
// 删除操作:标记删除状态。
XOrm.Delete(user) // 通过事务缓冲至提交队列中删除。
// 清除操作:标记清除状态
cond = XOrm.Cond("age < {0}", 18)
XOrm.Clear(user, cond) // 通过事务缓冲至提交队列中清除。
// 列举操作:从缓存和远端组合数据。
var users []*User
cond = XOrm.Cond("age > {0} && name contains {1}", 18, "test")
XOrm.List(&users, cond) // 依次检查会话缓存、全局缓存、远端数据。
注意: 1. 所有操作必须在 Watch() 和 Defer() 之间进行 2. 写入操作会同时更新会话缓存和全局缓存 3. 读取操作遵循缓存优先级:会话缓存 > 全局缓存 > 远端数据 4. 删除和清除操作仅做标记,实际删除在会话提交时执行 5. 列举操作可能会同时访问缓存和远端数据
3.2 指标监控
支持 Prometheus 指标监控,可以实时监控 CRUD 提交的性能和资源使用情况:
指标说明:
| 指标 | 类型 | 描述 |
|------|------|------|
| xorm_context_commit_queue | Gauge | 所有队列中等待提交的对象总数 |
| xorm_context_commit_total | Counter | 所有队列已经提交的对象总数 |
| xorm_context_commit_queue_{n} | Gauge | 第 n 个队列中等待提交的对象数量 |
| xorm_context_commit_total_{n} | Counter | 第 n 个队列已经提交的对象总数 |
3.3 可选配置
支持通过首选项配置对提交队列进行调整:
配置参数:
- XOrm/Context/Commit/Queue:提交队列的数量,默认为 CPU 核心数,-1 表示禁用提交队列
- XOrm/Context/Commit/Capacity:单个队列的容量,默认为 100000
配置示例:
{
"XOrm/Context/Commit/Queue": 8,
"XOrm/Context/Commit/Capacity": 100000
}
更多信息请参考模块文档。
Index ¶
- func Clear[T IModel](model T, cond ...*Condition)
- func Close()
- func Defer()
- func Delete[T IModel](model T)
- func Dump(models ...IModel)
- func Flush(gid ...int64)
- func Incre(model IModel, columnAndDelta ...any) int
- func List[T IModel](model T, writableAndCond ...any) []T
- func Meta(model IModel, cache bool, writable bool)
- func Print() string
- func Read[T IModel](model T, writableAndCond ...any) T
- func Watch(writable ...bool) int
- func Write[T IModel](model T)
- type Condition
- type IModel
- type Model
- func (md *Model[T]) AliasName() string
- func (md *Model[T]) Clear(cond ...*Condition) int
- func (md *Model[T]) Clone() IModel
- func (md *Model[T]) Count(cond ...*Condition) int
- func (md *Model[T]) Ctor(obj any)
- func (md *Model[T]) DataUnique() string
- func (md *Model[T]) DataValue(field string) any
- func (md *Model[T]) Delete() int
- func (md *Model[T]) Equals(model IModel) bool
- func (md *Model[T]) IsValid(value ...bool) bool
- func (md *Model[T]) Json() string
- func (md *Model[T]) List(rets any, cond ...*Condition) int
- func (md *Model[T]) Matchs(cond ...*Condition) bool
- func (md *Model[T]) Max(column ...string) int
- func (md *Model[T]) Min(column ...string) int
- func (md *Model[T]) ModelUnique() string
- func (md *Model[T]) OnDecode()
- func (md *Model[T]) OnEncode()
- func (md *Model[T]) OnQuery(action string, cond *orm.Condition) *orm.Condition
- func (md *Model[T]) Read(cond ...*Condition) bool
- func (md *Model[T]) TableName() string
- func (md *Model[T]) Write() int
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Clear ¶
Clear 根据条件批量标记数据模型为清除状态。 model 为要清除的数据模型,必须实现 IModel 接口。 cond 为可选的查询条件列表,用于匹配要清除的数据。
清除操作首先验证模型是否已注册,然后创建标记映射用于跟踪已处理的对象。 在会话内存清除阶段,遍历会话内存中的对象,对匹配条件的对象设置删除标记,并记录到标记映射中。 如果启用了缓存,在全局内存清除阶段,遍历全局内存中的对象,对匹配条件的对象设置删除标记。 对于未在会话内存中处理过的对象,会克隆到会话内存并设置相应的删除标记。
需要注意的是,清除操作是软删除,不会立即从内存中移除数据,被标记清除的数据在读取时会被忽略。 该函数是线程不安全的,操作相同的数据模型时,需要控制并发或使用适当的同步方式(如:Mutex)以确保操作的正确性。
func Defer ¶
func Defer()
Defer 结束 CRUD 操作监控。 函数获取当前 goroutine ID 并检索对应的上下文实例。 如果是读写操作,会自动对比 CRUD 前后的数据变更(新建、删除和修改等)。 然后对变更进行合批并路由到(基于 goroutine ID)指定的队列中进行异步提交。 对于只读操作,仅清理会话映射,不进行数据同步。
此函数应通过 defer 调用,确保每个 Watch 都有对应的 Defer。
func Delete ¶
func Delete[T IModel](model T)
Delete 标记数据模型为删除状态。 model 为要删除的数据模型,必须实现 IModel 接口。
删除操作首先验证模型是否已注册。如果启用了缓存,会在全局内存中查找对应的对象, 如果存在,则设置其删除标记为 true。 然后在会话内存中创建或获取会话对象,并设置删除标记为 true。
需要注意的是,删除操作是软删除,不会立即从内存中移除数据,被标记删除的数据在读取时会被忽略。 该函数是线程不安全的,操作相同的数据模型时,需要控制并发或使用适当的同步方式(如:Mutex)以确保操作的正确性。
func Flush ¶
func Flush(gid ...int64)
Flush 将等待指定的队列提交完成。 gid 参数为 goroutine ID,若未指定,则使用当前 goroutine ID, 若 gid 为 -1,则表示等待所有的队列提交完成。
func Incre ¶ added in v1.1.0
Incre 获取并自增指定列的最大值。model 参数为要操作的数据模型,必须实现 IModel 接口。 columnAndDelta 为可变参数,支持多种组合:无参数时自增主键且增量为 1;一个参数时,若为字符串则 指定列名且增量为 1,若为整数则使用主键并指定增量;两个参数时,第一个为列名(字符串),第二个为增量(整数)。
函数首先获取或创建模型的最大值缓存,然后解析参数确定目标列名和增量值。如果未指定列名,会尝试使用主键列,若无主键则报错。 获取当前最大值时优先使用缓存的值,如果缓存不存在,则从远端数据获取,最后计算并缓存新值。 函数返回自增后的新值,如果列名为空,则返回 0。
需要注意的是,缓存的最大值在程序重启后会重置。 该函数是线程安全的,可以确保单实例内的数据唯一性。
func List ¶
List 获取数据模型的列表。model 参数为要查询的数据模型,必须实现 IModel 接口。 writableAndCond 为可变参数,可包含布尔值(表示是否可写)和查询条件对象(*Condition 类型)。
函数首先验证模型是否已注册,然后解析参数获取可写标记和查询条件。查询数据时按照优先级依次从会话内存、全局内存和远端数据获取。 会话内存查询会过滤掉已标记删除的数据并应用查询条件; 全局内存查询会克隆数据到会话内存并处理覆盖数据; 远端数据查询会将数据同步到全局内存(如果启用缓存)和会话内存,并处理删除标记以确保数据一致性。 对于远端查询结果,函数会检查并使用会话内存和全局内存中的最新数据,移除被标记删除的数据,并添加仅在会话内存或全局内存中的匹配数据作为补充同步。 函数返回满足条件的数据模型切片,已被标记删除的数据将被过滤。
需要注意的是,返回的数据是原始数据的克隆,非条件列举可能导致数据不同步,建议避免在异步操作期间进行条件列举。 该函数是线程安全的,可以确保单实例内的数据一致性。
func Meta ¶ added in v1.1.0
Meta 注册一个模型。 model 为模型实例。 cache 指定是否缓存。 writable 指定是否可写。 如果模型为 nil 或已注册,将触发 panic。
func Print ¶
func Print() string
Print 生成缓存的文本信息。 返回包含以下信息的字符串:
[Data]: 缓存数据 [List]: 列举状态 [Incre]: 自增记录 [Lock]: 数据锁状态
func Read ¶
Read 从数据源读取数据模型。model 参数为要读取的数据模型,必须实现 IModel 接口。 writableAndCond 为可变参数,可包含布尔值(表示是否可写)和查询条件对象(*Condition 类型)。
函数根据是否有查询条件采用不同的读取策略。对于精确查找(无查询条件),首先尝试从会话内存中读取, 如果启用缓存则尝试从全局内存中读取,最后从远端数据读取。对于模糊查找(有查询条件), 仅缓存模式下先查询会话内存再查询全局内存;其他模式则按照会话列表、全局列表、远端数据的顺序查找。
函数返回读取到的数据模型,如果数据被标记为删除,模型的 IsValid 将被设置为 false。
该函数是线程安全的,可以确保单实例内的数据一致性。
Types ¶
type Condition ¶
type Condition struct {
Base *orm.Condition // 基础条件
Limit int // 分页限定
Offset int // 分页偏移
// contains filtered or unexported fields
}
Condition 表示一个查询条件,包含基础条件和分页信息。
type IModel ¶
type IModel interface {
// Ctor 执行模型的构造初始化。
// obj 为模型实例,必须是实现了 IModel 接口的结构体指针。
// 此方法会在模型创建时自动调用,用于初始化模型的基本状态。
Ctor(obj any)
// OnEncode 在对象编码前调用。
// 子类可以重写此方法以实现自定义的编码逻辑。
// 通常用于在数据写入前对字段进行预处理。
OnEncode()
// OnDecode 在对象解码后调用。
// 子类可以重写此方法以实现自定义的解码逻辑。
// 通常用于在数据读取后对字段进行后处理。
OnDecode()
// OnQuery 在执行查询时调用。
// 子类可以重写此方法以实现自定义的查询逻辑。
// 通常用于在执行查询前追加一个全局的条件,如数据分区等。
// action 是查询的类型,包括:Count、Max、Min、Read、List、Delete、Clear。
// cond 是查询的条件,传入的值可能为空。
// 返回执行查询的最终条件。
OnQuery(action string, cond *orm.Condition) *orm.Condition
// AliasName 返回数据库别名。
// 返回值用于标识不同的数据库连接。
// 此方法必须由子类实现。
AliasName() string
// TableName 返回数据表名称。
// 返回值用于标识数据库中的具体表。
// 此方法必须由子类实现。
TableName() string
// ModelUnique 返回模型的唯一标识。
// 返回值格式为 "数据库别名_表名"。
// 用于在缓存和其他场景中唯一标识一个模型类型。
ModelUnique() string
// DataUnique 返回数据记录的唯一标识。
// 返回值格式为 "模型标识_主键值"。
// 用于在缓存和其他场景中唯一标识一条记录。
DataUnique() string
// DataValue 获取指定字段的值。
// field 为字段名称。
// 返回字段值,若字段不存在则返回 nil。
DataValue(field string) any
// Count 统计符合条件的记录数量。
// cond 为可选的查询条件。
// 返回记录数量,如果发生错误则返回 -1。
Count(cond ...*Condition) int
// Max 获取指定列的最大值。
// column 为可选的列名,若不指定则使用主键列。
// 返回最大值,如果发生错误则返回 -1。
Max(column ...string) int
// Min 获取指定列的最小值。
// column 为可选的列名,若不指定则使用主键列。
// 返回最小值,如果发生错误则返回 -1。
Min(column ...string) int
// Write 写入或更新当前记录。
// 在写入前会调用 OnEncode 进行编码处理。
// 返回受影响的行数,如果发生错误则返回 -1。
Write() int
// Read 读取符合条件的记录。
// cond 为可选的查询条件,若不指定则使用主键作为查询条件。
// 读取成功后会调用 OnDecode 进行解码处理。
// 返回是否成功读取到记录。
Read(cond ...*Condition) bool
// List 查询符合条件的记录列表。
// rets 必须是指向切片的指针,用于存储查询结果。
// cond 为可选的查询条件,可以指定偏移量和限制数量。
// 返回查询到的记录数量,如果发生错误则返回 -1。
List(rets any, cond ...*Condition) int
// Delete 删除当前记录。
// 使用主键作为删除条件。
// 返回受影响的行数,如果发生错误则返回 -1。
Delete() int
// Clear 清理符合条件的记录。
// cond 为可选的查询条件,若不指定则清理所有记录。
// 返回受影响的行数,如果发生错误则返回 -1。
// 注意:MySQL Connector 最大的参数是 65535,清理大量数据时可能会触发错误:Prepared statement contains too many placeholders,解决方法为分批执行清理。
Clear(cond ...*Condition) int
// IsValid 检查或设置对象的有效性。
// value 为可选的设置值,如果提供则设置对象的有效性状态。
// 返回对象当前的有效性状态。
IsValid(value ...bool) bool
// Clone 创建对象的深度拷贝。
// 拷贝后会调用 OnDecode 进行解码处理。
// 返回新的对象实例,如果拷贝失败则返回 nil。
Clone() IModel
// Json 将对象转换为 JSON 字符串。
// 返回 JSON 格式的字符串表示。
Json() string
// Equals 比较两个对象是否相等。
// model 为待比较的对象。
// 返回两个对象的所有数据库字段是否完全相等。
Equals(model IModel) bool
// Matchs 检查对象是否匹配指定条件。
// cond 为可选的匹配条件。
// 返回对象是否满足所有条件。
Matchs(cond ...*Condition) bool
}
IModel 定义了数据模型的基础接口。 实现此接口的类型可以参与数据库的 CRUD 操作和缓存管理。
type Model ¶
type Model[T any] struct { // contains filtered or unexported fields }
Model 实现了 IModel 接口的基础模型。 T 为具体的模型类型,必须是结构体类型。 所有的具体模型类型都应该嵌入此类型。
func (*Model[T]) Clear ¶
Clear 清理符合条件的记录。 cond 为可选的查询条件,若不指定则清理所有记录。 返回受影响的行数,如果发生错误则返回 -1。 注意:MySQL Connector 最大的参数是 65535,清理大量数据时可能会触发错误:Prepared statement contains too many placeholders,解决方法为分批执行清理。
func (*Model[T]) DataUnique ¶
DataUnique 返回数据记录的唯一标识。 返回值格式为 "模型标识_主键值"。 如果模型信息或主键未找到,将返回空字符串。
func (*Model[T]) List ¶
List 查询符合条件的记录列表。 rets 必须是指向切片的指针,用于存储查询结果。 cond 为可选的查询条件,可以指定偏移量和限制数量。 返回查询到的记录数量,如果发生错误则返回 -1。
func (*Model[T]) ModelUnique ¶
ModelUnique 返回模型的唯一标识。 返回值格式为 "数据库别名_表名"。
func (*Model[T]) OnDecode ¶
func (md *Model[T]) OnDecode()
OnDecode 在对象解码后调用。 子类可以重写此方法以实现自定义的解码逻辑。 通常用于在数据读取后对字段进行后处理。
func (*Model[T]) OnEncode ¶
func (md *Model[T]) OnEncode()
OnEncode 在对象编码前调用。 子类可以重写此方法以实现自定义的编码逻辑。 通常用于在数据写入前对字段进行预处理。
func (*Model[T]) OnQuery ¶
OnQuery 在执行查询时调用。 子类可以重写此方法以实现自定义的查询逻辑。 通常用于在执行查询前追加一个全局的条件,如数据分区等。 action 是查询的类型,包括:Count、Max、Min、Read、List、Delete、Clear。 cond 是查询的条件,传入的值可能为空。 返回执行查询的最终条件。
func (*Model[T]) Read ¶
Read 读取符合条件的记录。 cond 为可选的查询条件,若不指定则使用主键作为查询条件。 读取成功后会调用 OnDecode 进行解码处理。 返回是否成功读取到记录。