shadow路由不生效需排查四点:一是确认sql是否经分片引擎(开启sql-show日志验证);二是检查表名大小写及别名导致匹配失败;三是确保shadow-property由业务显式注入(如setshadow(true));四是写操作需显式染色且配置shadow-insert-allowed=true。

shadow 表路由不生效?先确认 shadow-rule 是否命中真实 SQL 路由路径
ShardingSphere 的 shadow 功能本质是「路由拦截」,不是请求代理。它只在 SQL 解析后、实际分片路由前介入,如果 SQL 没走分片引擎(比如直连单库、用了 default-data-source、或被 sql-comment-parser 误判为非标准 SQL),shadow 规则压根不会触发。
实操建议:
- 开启
props.sql-show=true和props.shadow-sql-show=true,观察日志里是否出现[Shadow] Route to shadow data source这类标记 - 确保目标表名在
shadow-table-rules中显式声明,且表名大小写与 SQL 中完全一致(ShardingSphere 默认区分大小写) - 避免在 SQL 中用别名覆盖原表名,例如
SELECT * FROM t_order AS o—— 此时路由依据的是o,而非t_order,shadow规则无法匹配
流量染色靠 shadow-property,但 header 透传失败很常见
ShardingSphere 不主动读取 HTTP Header 或 RPC 上下文,shadow-property 的值必须由业务代码显式注入到 ThreadLocal 或通过 SPI 注入的 ShadowDataSource 上下文。常见错误是以为加个 X-Shadow:true 就能自动生效。
实操建议:
- 使用
ShadowConnection.setShadow(true)是最直接的方式,适合单元测试或脚本调用场景 - Web 层需手动提取 header 并调用
ShadowProperty.setShadow(true),注意清理ThreadLocal防止污染下游线程池 - Spring Cloud 微服务中,若用 OpenFeign,需配合
RequestInterceptor把 shadow 标识透传到下游,否则染色只在第一跳有效
shadow-datasource 和真实数据源共存时,事务和连接泄漏风险高
ShardingSphere 的 shadow 数据源默认不参与分布式事务管理(如 Seata、XA),也不受 Spring @Transactional 的连接复用机制控制。一旦在同一个事务里混用 shadow 和非 shadow 数据源,极易出现连接未关闭、事务回滚不一致、甚至影子库写入真实库。
实操建议:
- 禁止在
@Transactional方法内同时操作 shadow 表和普通表;如需比对,改用「先查主库 → 再查影子库」的非事务方式 - 为
shadow-datasource单独配置最小空闲连接数为0,防止连接长期滞留(影子库通常只读/低频) - 监控
ShadowDataSource的activeCount,异常升高往往意味着连接未释放,根源常是 try-with-resources 缺失或异步线程未正确传递上下文
测试验证阶段最容易忽略 shadow 的「只读豁免」逻辑
ShardingSphere 默认对 SELECT 自动启用 shadow 路由,但 INSERT/UPDATE/DELETE 必须显式染色才走影子库——这是为了防止脏写。很多团队测试时只跑查询,误以为 shadow 已全量生效,上线后才发现写流量没进影子库,比对失效。
实操建议:
- 测试用例必须覆盖
INSERT INTO ... SELECT类混合语句,这类语句会被判定为写操作,不染色就不进 shadow 库 - 用
SHOW SHADOW RULES命令(ShardingSphere-Proxy)或ShadowRuleConfiguration的 API 检查当前规则是否启用了shadow-insert-allowed=true(5.3.0+ 可配) - 影子库 DDL 同步不能依赖 ShardingSphere,必须单独维护;若影子库缺字段,
INSERT会直接报Column not found错误,而非静默降级
事情说清了就结束。










