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

  1. Split the multi-table UPDATE into separate single-table UPDATE statements
  2. Route the statement directly to a backend MySQL (bypass Mycat routing) if it only touches one data node
  3. 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

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


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)