OOro

分片

把模型查询和写入路由到配置好的分片连接。

分片是核心路由能力。它通过分片策略把模型查询映射到多个连接中的一个。

配置分片

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 会把查询扇出到所有配置的分片连接。对于 GetFirst 和分页,它会执行全局合并:先汇总所有分片的行,按查询的 ORDER BY 排序,再在合并后的结果上全局应用 LIMIT / OFFSET。建议只用于查询或受控维护流程。

:::note[全局排序与分页] 全分片读取现在会做全局合并和排序,而不再按分片拼接各自的结果。早期版本会在每个分片上分别应用 LIMIT / OFFSET,导致跨分片的排序和分页结果错误。由于合并发生在内存中,任何有序的全分片读取都必须显式给出 ORDER BYAllShards() 上的 First() 返回全局第一行;未设置 ORDER BY 时会返回 oro.ErrOrderRequired。 :::

跨分片聚合

AllShards() 上的 Count 是支持的,会把各分片的计数累加:

total, err := db.Use[Order]().
    AllShards().
    Where("Status", "paid").
    Count(ctx)

SumAvgMinMax 无法通过合并各分片的值得到正确结果,因此它们在 AllShards() 上现在会返回 oro.ErrUnsupported,而不再悄悄返回单个分片的结果。如果确实需要跨分片计算这些值,请在应用层(或逐分片)处理。

事务

单个事务不能跨多个分片。如果写入流程需要多个分片,应该在应用层协调。

Tenant 扩展集成

extensions/tenant 可以自动向分片路由提供租户值。如果分片按租户路由,参考 Tenant 租户扩展

编辑此页