Documentation
¶
Overview ¶
XOrm 拓展了 Beego 的 ORM 功能,同时实现了基于上下文的事务机制,提高了数据操作的效率。
功能特性
- 多源配置:通过解析首选项中的配置自动初始化数据库连接
- 数据模型:提供了面向对象的模型设计及常用的数据操作
- 事务操作:基于上下文的事务机制,支持缓存和并发控制
使用手册
1. 多源配置
配置说明:
- 配置键名:Orm/Source/<数据库类型>/<数据库别名>
- 支持 MySQL、PostgreSQL、SQLite3 等(Beego ORM 支持的类型)
- 配置参数:
- Addr:数据源地址
- Pool:连接池大小
- Conn:最大连接数
配置示例:
{ "Orm/Source/MySQL/Main": { "Addr": "root:123456@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&loc=Local", "Pool": 1, "Conn": 1 }, "Orm/Source/PostgreSQL/Log": { "Addr": "postgres://user:pass@localhost:5432/dbname?sslmode=disable", "Pool": 2, "Conn": 10 }, "Orm/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_commit_queue | Gauge | 所有队列中等待提交的对象总数 | | xorm_commit_total | Counter | 所有队列已经提交的对象总数 | | xorm_commit_queue_{n} | Gauge | 第 n 个队列中等待提交的对象数量 | | xorm_commit_total_{n} | Counter | 第 n 个队列已经提交的对象总数 |
3.3 可选配置
支持通过首选项配置对提交队列进行调整:
配置参数:
- Orm/Commit/Queue:提交队列的数量,默认为 CPU 核心数,-1 表示禁用提交队列
- Orm/Commit/Queue/Capacity:单个队列的容量,默认为 100000
配置示例:
{ "Orm/Commit/Queue": 8, "Orm/Commit/Queue/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 ¶
Incre 获取并自增指定列的最大值。model 参数为要操作的数据模型,必须实现 IModel 接口。 columnAndDelta 为可变参数,支持多种组合:无参数时自增主键且增量为 1;一个参数时,若为字符串则 指定列名且增量为 1,若为整数则使用主键并指定增量;两个参数时,第一个为列名(字符串),第二个为增量(整数)。
函数首先获取或创建模型的最大值缓存,然后解析参数确定目标列名和增量值。如果未指定列名,会尝试使用主键列,若无主键则报错。 获取当前最大值时优先使用缓存的值,如果缓存不存在,则从远端数据获取,最后计算并缓存新值。 函数返回自增后的新值,如果列名为空,则返回 0。
需要注意的是,缓存的最大值在程序重启后会重置。 该函数是线程安全的,可以确保单实例内的数据唯一性。
func List ¶
List 获取数据模型的列表。model 参数为要查询的数据模型,必须实现 IModel 接口。 writableAndCond 为可变参数,可包含布尔值(表示是否可写)和查询条件对象(*Condition 类型)。
函数首先验证模型是否已注册,然后解析参数获取可写标记和查询条件。查询数据时按照优先级依次从会话内存、全局内存和远端数据获取。 会话内存查询会过滤掉已标记删除的数据并应用查询条件; 全局内存查询会克隆数据到会话内存并处理覆盖数据; 远端数据查询会将数据同步到全局内存(如果启用缓存)和会话内存,并处理删除标记以确保数据一致性。 对于远端查询结果,函数会检查并使用会话内存和全局内存中的最新数据,移除被标记删除的数据,并添加仅在会话内存或全局内存中的匹配数据作为补充同步。 函数返回满足条件的数据模型切片,已被标记删除的数据将被过滤。
需要注意的是,返回的数据是原始数据的克隆,非条件列举可能导致数据不同步,建议避免在异步操作期间进行条件列举。 该函数是线程安全的,可以确保单实例内的数据一致性。
func Meta ¶ added in v0.0.2
Meta 注册一个模型。 model 为模型实例。 cache 指定是否缓存。 writable 指定是否可写。 如果模型为 nil 或已注册,将触发 panic。
func Print ¶ added in v0.0.2
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 ¶ added in v0.0.8
OnQuery 在执行查询时调用。 子类可以重写此方法以实现自定义的查询逻辑。 通常用于在执行查询前追加一个全局的条件,如数据分区等。 action 是查询的类型,包括:Count、Max、Min、Read、List、Delete、Clear。 cond 是查询的条件,传入的值可能为空。 返回执行查询的最终条件。
func (*Model[T]) Read ¶
Read 读取符合条件的记录。 cond 为可选的查询条件,若不指定则使用主键作为查询条件。 读取成功后会调用 OnDecode 进行解码处理。 返回是否成功读取到记录。