{"record":{"id":"dbd9d9cf193f4e55","repo":"MyCATApache/Mycat-Server","slug":"can-t-lock-multi-table","errorCode":null,"errorMessage":"can't lock multi-table","messagePattern":"can't lock multi-table","errorType":"exception","errorClass":"SQLNonTransientException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/mycat/route/parser/druid/impl/DruidLockTableParser.java","lineNumber":75,"sourceCode":"\t\tsql = sql.replaceAll(\"\\n\", \" \").replaceAll(\"\\t\", \" \");\n\t\tString[] stmts = SplitUtil.split(sql, ',', true);\n\t\t// 如果命令中存在\",\"，则按多表锁的语句来处理\n\t\tif (stmts.length > 1) {\n\t\t\tString tmpStmt = null;\n\t\t\tString tmpWords[] = null;\n\t\t\tfor (int i = 1; i < stmts.length; i ++) {\n\t\t\t\ttmpStmt = stmts[i];\n\t\t\t\ttmpWords = SplitUtil.split(tmpStmt, ' ', true);\n\t\t\t\tif (tmpWords.length==2 && (\"READ\".equalsIgnoreCase(tmpWords[1]) || \"WRITE\".equalsIgnoreCase(tmpWords[1]))) {\n\t\t\t\t\t// 如果符合多表锁的语法，则继续，并在最后提示不能多表锁！\n\t\t\t\t\tcontinue;\n\t\t\t\t} else {\n\t\t\t\t\t// 如果不符合多表锁的语法，则提示语法错误和不能多表锁！\n\t\t\t\t\tthrow new SQLNonTransientException(\"You have an error in your SQL syntax, don't support lock multi tables!\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tLOGGER.error(\"can't lock multi-table\");\n\t\t\tthrow new SQLNonTransientException(\"can't lock multi-table\");\n\t\t}\n\t}\n}\n","sourceCodeStart":57,"sourceCodeEnd":79,"githubUrl":"https://github.com/MyCATApache/Mycat-Server/blob/65f8d8beb752f935752f2a0eec0ab017facab9ef/src/main/java/io/mycat/route/parser/druid/impl/DruidLockTableParser.java#L57-L79","documentation":"Also in visitorParse: after the syntax-tolerant loop over extra lock items, MyCat still logs 'can't lock multi-table' and throws SQLNonTransientException with that message whenever the statement locks more than one table. Multi-table LOCK TABLES is simply not supported for routing.","triggerScenarios":"visitorParse on any LOCK TABLES statement that passed the per-item syntax check but contains multiple tables (e.g. `LOCK TABLES a WRITE, b READ`).","commonSituations":"Application code that mirrors MySQL multi-table locking idioms; DBA scripts run through MyCat; ORMs locking several entities at once.","solutions":["Split into separate single-table LOCK TABLES statements","Replace locking with transactional isolation (SELECT ... FOR UPDATE) within one transaction","Route the statement directly to a single MySQL datanode instead of through MyCat"],"exampleFix":"// before\nLOCK TABLES a WRITE, b READ;\n// after\nLOCK TABLES a WRITE;\nLOCK TABLES b READ;","handlingStrategy":"validation","validationCode":"int tableCount = countLockItems(sql); if (tableCount > 1) throw new IllegalArgumentException(\"lock at most one table per statement\");","typeGuard":null,"tryCatchPattern":"try { route(sql); } catch (SQLNonTransientException e) { if (e.getMessage().equals(\"can't lock multi-table\")) { lockOneTableAtATime(sql); } else throw e; }","preventionTips":["Design locking logic around single-table statements","Use transactional isolation instead of table locks where possible","Keep multi-table lock scripts off the MyCat path"],"tags":["sql","lock","unsupported","multi-table"],"backgroundTag":"unsupported-operation","analyzedSha":"65f8d8beb752f935752f2a0eec0ab017facab9ef","analyzedAt":"2026-09-11T00:12:21.696Z","contentChangedAt":"2026-09-11T00:12:21.696Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}