MyCATApache/Mycat-Server · error · SQLNonTransientException
"multi table related update not supported,tables:" +…
Error message
"multi table related update not supported,tables:" + ctx.getTables()
What it means
Mycat limits an UPDATE statement to at most one sharding table: multi-table (join) UPDATEs cannot be atomically routed across shards. If ctx.getTables() shows more than one table and the schema is not configured as noSharding, the parser throws SQLNonTransientException.
Solutions
- Split the multi-table UPDATE into separate single-table UPDATE statements
- Route the statement directly to a backend MySQL (bypass Mycat routing) if it only touches one data node
- Configure the involved tables/schema for non-sharding (noSharding) so the statement is passed through
Example fix
-- before UPDATE orders o JOIN users u ON o.uid=u.id SET o.status=2 WHERE u.tier=3; -- after (split) UPDATE users SET tier = tier WHERE id=...; UPDATE orders SET status=2 WHERE uid IN (SELECT ... executed separately);
Defensive patterns
Strategy: validation
Validate before calling
Set<String> tables = extractTables(updateSql);
if (tables.size() > 1) throw new IllegalArgumentException("split multi-table UPDATE before sending to mycat"); Try / catch
try { route(...); } catch (SQLNonTransientException e) { if (e.getMessage().startsWith("multi table related update")) { splitAndExecute(); } else throw e; } Prevention
- Split multi-table UPDATEs into single-table statements in app code
- Wrap cross-table updates in application-level transactions instead of MySQL join-update syntax
- Lint SQL migrations for multi-table UPDATE before running against Mycat
When it happens
Trigger: Executing `UPDATE t1 JOIN t2 SET ... WHERE ...` or `UPDATE t1, t2 SET ...` where both tables are in the schema and the schema is not marked noSharding (isNoSharding() == false).
Common situations: MySQL-specific multi-table UPDATE scripts migrated to Mycat; batch data-fix SQL written for a single backend; ORMs generating correlated multi-table updates.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- " find no Route:" + ctx.getSql()
- "Sharding column can't be updated " + tableName + "->" +…
- "Parent relevant column can't be updated " + tableName +…
- can't find any valid datanode : -> ->
- find no Route:
AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11).
Data as JSON: /api/errors/b7c06c417f8b390d.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/route/parser/druid/impl/DruidUpdateParser.java:33
import io.mycat.cache.DefaultLayedCachePool;
import io.mycat.config.model.SchemaConfig;
import io.mycat.config.model.TableConfig;
import io.mycat.route.RouteResultset;
import io.mycat.route.util.RouterUtil;
import io.mycat.util.StringUtil;
import java.sql.SQLNonTransientException;
import java.util.List;
import java.util.Map;
public class DruidUpdateParser extends DefaultDruidParser {
@Override
public void statementParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt) throws SQLNonTransientException {
//这里限制了update分片表的个数只能有一个
if (ctx.getTables() != null && getUpdateTableCount() > 1 && !schema.isNoSharding()) {
String msg = "multi table related update not supported,tables:" + ctx.getTables();
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
MySqlUpdateStatement update = (MySqlUpdateStatement) stmt;
String tableName = StringUtil.removeBackquote(update.getTableName().getSimpleName().toUpperCase());
TableConfig tc = schema.getTables().get(tableName);
if (RouterUtil.isNoSharding(schema, tableName)) {//整个schema都不分库或者该表不拆分
RouterUtil.routeForTableMeta(rrs, schema, tableName, rrs.getStatement());
rrs.setFinishedRoute(true);
return;
}
String partitionColumn = tc.getPartitionColumn();
String joinKey = tc.getJoinKey();
if (tc.isGlobalTable() || (partitionColumn == null && joinKey == null)) {
//修改全局表 update 受影响的行数
RouterUtil.routeToMultiNode(false, rrs, tc.getDataNodes(), rrs.getStatement(), tc.isGlobalTable());
rrs.setFinishedRoute(true);View on GitHub (pinned to 65f8d8beb7)