gin和gorm均不自动支持分库分表,必须在handler或service层手动实现分片路由、连接选择与结果聚合;需按请求动态获取绑定分片的*gorm.db实例,跨分片查询、join、分页及事务均需应用层自行处理。

Gin 本身不参与分库分表,GORM 也不自动做分片路由——所谓「自适应」必须由你手动控制连接、计算分片键、切换 db 实例,没有魔法开关。
分片逻辑必须在 Gin handler 或 service 层注入
Gin 的中间件和 handler 是唯一可控的执行入口,所有分片决策(比如用 user_id 算 shardID、查缓存选库)都得在这里完成。GORM 的 *gorm.DB 是无状态连接池抽象,不能跨请求复用分片上下文。
- 别在全局初始化时硬编码
db,而应按请求动态获取分片后的*gorm.DB - 推荐把分片路由封装成函数,例如
GetShardDB(userID uint64) *gorm.DB,内部查map[shardID]*gorm.DB缓存 - 避免每次请求都新建
*gorm.DB:连接池开销大,且 GORM 不支持运行时切换底层*sql.DB - 若用
gin.Context传参,记得用c.Set("shard_db", db)而非c.Set("db", db),防止被其他中间件覆盖
GORM 模型层无法隐藏分片细节
gorm.Model(&User{}) 或 db.Where("id = ?", id).First(&u) 这类调用,默认走的是你传入的 *gorm.DB 实例——它已经绑定了某个分片库。GORM 不会解析 SQL 里的 WHERE 条件去重路由。
- 跨分片查询(如
SELECT COUNT(*) FROM user)必须手动遍历所有分片库执行db.Table("sys_user_0").Count(&count),再累加 -
JOIN操作几乎不可行:GORM 的Preload和Joins都只作用于当前db实例,跨库 JOIN 会报错或返回空 - 分页需两层:先在各分片查出 ID 列表(带
LIMIT OFFSET),再合并排序后取最终结果,或改用游标分页 - 事务仅限单分片:
db.Transaction()有效,但跨分片事务必须退化为本地事务 + 最终一致性补偿(如发 MQ、写对账表)
ShardingSphere 与纯 GORM 方案的本质区别
如果你用 ShardingSphere-Proxy,Gin + GORM 可以保持原样;但若走纯 Go 实现,就得自己扛路由、聚合、失败重试——这两条路完全不兼容。
- ShardingSphere 配置中的
algorithm-expression: sys_user_${user_id % 4}是服务端解析,GORM 发出的 SQL 不需要改,前提是你的 DSN 指向 Proxy 地址而非真实 MySQL - 纯 GORM 方案下,
sys_user表名必须硬编码为sys_user_0、sys_user_1等,否则 GORM 会报Table 'xxx.sys_user' doesn't exist - ShardingSphere 支持分布式主键(如
SNOWFLAKE),而 GORM 默认AutoIncrement在分片表里会冲突,必须关掉并用外部 ID 生成器 - 连接池管理不同:ShardingSphere 自带连接池,GORM 则要为每个分片库维护独立
*gorm.DB,注意SetMaxOpenConns总和别超 MySQLmax_connections
真正麻烦的不是算 shardID,而是跨分片场景下的语义一致性——比如一个订单含多个商品,它们可能落在不同库,查详情时得并发拉多个库再 merge。这种逻辑不会因为用了 Gin 或 GORM 就消失,只会被掩盖得更难 debug。











