{"record":{"id":"b7c06c417f8b390d","repo":"MyCATApache/Mycat-Server","slug":"multi-table-related-update-not-supported-tables-b7c06c","errorCode":null,"errorMessage":"\"multi table related update not supported,tables:\" + ctx.getTables()","messagePattern":"\"multi table related update not supported,tables:\" \\+ ctx\\.getTables\\(\\)","errorType":"exception","errorClass":"SQLNonTransientException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/mycat/route/parser/druid/impl/DruidUpdateParser.java","lineNumber":33,"sourceCode":"import io.mycat.cache.DefaultLayedCachePool;\nimport io.mycat.config.model.SchemaConfig;\nimport io.mycat.config.model.TableConfig;\nimport io.mycat.route.RouteResultset;\nimport io.mycat.route.util.RouterUtil;\nimport io.mycat.util.StringUtil;\n\nimport java.sql.SQLNonTransientException;\nimport java.util.List;\nimport java.util.Map;\n\npublic class DruidUpdateParser extends DefaultDruidParser {\n    @Override\n    public void statementParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt) throws SQLNonTransientException {\n        //这里限制了update分片表的个数只能有一个\n        if (ctx.getTables() != null && getUpdateTableCount() > 1 && !schema.isNoSharding()) {\n            String msg = \"multi table related update not supported,tables:\" + ctx.getTables();\n            LOGGER.warn(msg);\n            throw new SQLNonTransientException(msg);\n        }\n        MySqlUpdateStatement update = (MySqlUpdateStatement) stmt;\n        String tableName = StringUtil.removeBackquote(update.getTableName().getSimpleName().toUpperCase());\n\n        TableConfig tc = schema.getTables().get(tableName);\n\n        if (RouterUtil.isNoSharding(schema, tableName)) {//整个schema都不分库或者该表不拆分\n            RouterUtil.routeForTableMeta(rrs, schema, tableName, rrs.getStatement());\n            rrs.setFinishedRoute(true);\n            return;\n        }\n\n        String partitionColumn = tc.getPartitionColumn();\n        String joinKey = tc.getJoinKey();\n        if (tc.isGlobalTable() || (partitionColumn == null && joinKey == null)) {\n            //修改全局表 update 受影响的行数\n            RouterUtil.routeToMultiNode(false, rrs, tc.getDataNodes(), rrs.getStatement(), tc.isGlobalTable());\n            rrs.setFinishedRoute(true);","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/MyCATApache/Mycat-Server/blob/65f8d8beb752f935752f2a0eec0ab017facab9ef/src/main/java/io/mycat/route/parser/druid/impl/DruidUpdateParser.java#L15-L51","documentation":"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.","triggerScenarios":"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).","commonSituations":"MySQL-specific multi-table UPDATE scripts migrated to Mycat; batch data-fix SQL written for a single backend; ORMs generating correlated multi-table updates.","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"],"exampleFix":"-- before\nUPDATE orders o JOIN users u ON o.uid=u.id SET o.status=2 WHERE u.tier=3;\n-- after (split)\nUPDATE users SET tier = tier WHERE id=...;\nUPDATE orders SET status=2 WHERE uid IN (SELECT ... executed separately);","handlingStrategy":"validation","validationCode":"Set<String> tables = extractTables(updateSql);\nif (tables.size() > 1) throw new IllegalArgumentException(\"split multi-table UPDATE before sending to mycat\");","typeGuard":null,"tryCatchPattern":"try { route(...); } catch (SQLNonTransientException e) { if (e.getMessage().startsWith(\"multi table related update\")) { splitAndExecute(); } else throw e; }","preventionTips":["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"],"tags":["mysql","routing","sharding","update"],"backgroundTag":"unsupported-operation","analyzedSha":"65f8d8beb752f935752f2a0eec0ab017facab9ef","analyzedAt":"2026-09-11T00:12:21.696Z","contentChangedAt":"2026-09-11T00:12:21.696Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}