分片
把模型查询和写入路由到配置好的分片连接。
分片是核心路由能力。它通过分片策略把模型查询映射到多个连接中的一个。
配置分片
db, err := oro.Open(oro.Config{
Connections: map[string]oro.ConnectionConfig{
"orders_0": {Driver: mysql.Open(dsn0)},
"orders_1": {Driver: mysql.Open(dsn1)},
},
Shards: map[string]oro.ShardConfig{
"orders": {
Connections: []string{"orders_0", "orders_1"},
Strategy: oro.ModShard("TenantID"),
},
},
})
ModShard(field) 会把整数类字段按连接数量取模,得到目标分片连接。
模型分片
模型在 Define 中选择分片组:
type Order struct {
oro.Model
TenantID uint64
Code string
Total uint
}
func (Order) Define(s *oro.SchemaBuilder) {
s.Table("orders")
s.Shard("orders", "TenantID")
s.Field("TenantID").UnsignedBigInt().Index()
s.Field("Code").String().Unique()
s.Field("Total").Uint()
}
Shard 传入的是 Go 字段名。
查询单分片
显式传入分片值:
orders, err := db.Use[Order]().
Shard(oro.Map{"TenantID": uint64(10)}).
Where("Code", "A001").
Get(ctx)
写入也需要分片值:
created, err := db.Use[Order]().
Shard(oro.Map{"TenantID": uint64(10)}).
Create(ctx, &Order{TenantID: 10, Code: "A001", Total: 120})
分片模型没有提供分片值时,Oro 返回 oro.ErrShardRequired。
查询全部分片
读类扇出查询可以使用 AllShards():
orders, err := db.Use[Order]().
AllShards().
Where("Status", "paid").
OrderBy("Code").
Get(ctx)
AllShards 会把查询扇出到所有配置的分片连接。对于 Get、First 和分页,它会执行全局合并:先汇总所有分片的行,按查询的 ORDER BY 排序,再在合并后的结果上全局应用 LIMIT / OFFSET。建议只用于查询或受控维护流程。
:::note[全局排序与分页]
全分片读取现在会做全局合并和排序,而不再按分片拼接各自的结果。早期版本会在每个分片上分别应用 LIMIT / OFFSET,导致跨分片的排序和分页结果错误。由于合并发生在内存中,任何有序的全分片读取都必须显式给出 ORDER BY。AllShards() 上的 First() 返回全局第一行;未设置 ORDER BY 时会返回 oro.ErrOrderRequired。
:::
跨分片聚合
AllShards() 上的 Count 是支持的,会把各分片的计数累加:
total, err := db.Use[Order]().
AllShards().
Where("Status", "paid").
Count(ctx)
Sum、Avg、Min、Max 无法通过合并各分片的值得到正确结果,因此它们在 AllShards() 上现在会返回 oro.ErrUnsupported,而不再悄悄返回单个分片的结果。如果确实需要跨分片计算这些值,请在应用层(或逐分片)处理。
事务
单个事务不能跨多个分片。如果写入流程需要多个分片,应该在应用层协调。
Tenant 扩展集成
extensions/tenant 可以自动向分片路由提供租户值。如果分片按租户路由,参考 Tenant 租户扩展。