{"record":{"id":"4a07e4ed5bf340c5","repo":"MyCATApache/Mycat-Server","slug":"lock-type-must-be-write-or-read-4a07e4","errorCode":null,"errorMessage":"\"lock type must be write or read\"","messagePattern":"\"lock type must be write or read\"","errorType":"exception","errorClass":"SQLNonTransientException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/mycat/route/parser/druid/impl/DruidLockTableParser.java","lineNumber":39,"sourceCode":" * @author songdabin\n */\npublic class DruidLockTableParser extends DefaultDruidParser implements DruidParser {\n\t@Override\n\tpublic void statementParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt)\n\t\t\tthrows SQLNonTransientException {\n\t\tMySqlLockTableStatement lockTableStat = (MySqlLockTableStatement)stmt;\n\t\tString table = lockTableStat.getItems().get(0).getTableSource().toString().toUpperCase();\n\t\tTableConfig tableConfig = schema.getTables().get(table);\n\t\tif (tableConfig == null) {\n\t\t\tString msg = \"can't find table define of \" + table + \" in schema:\" + schema.getName();\n\t\t\tLOGGER.warn(msg);\n\t\t\tthrow new SQLNonTransientException(msg);\n\t\t}\n\t\tLockType lockType = lockTableStat.getItems().get(0).getLockType();\n\t\tif (LockType.WRITE != lockType && LockType.READ != lockType) {\n\t\t\tString msg = \"lock type must be write or read\";\n\t\t\tLOGGER.warn(msg);\n\t\t\tthrow new SQLNonTransientException(msg);\n\t\t}\n\t\tList<String> dataNodes = tableConfig.getDataNodes();\n\t\tRouteResultsetNode[] nodes = new RouteResultsetNode[dataNodes.size()];\n\t\tfor (int i = 0; i < dataNodes.size(); i ++) {\n\t\t\tnodes[i] = new RouteResultsetNode(dataNodes.get(i), ServerParse.LOCK, stmt.toString());\n\t\t}\n\t\trrs.setNodes(nodes);\n\t\trrs.setFinishedRoute(true);\n\t}\n\t\n\t@Override\n\tpublic void visitorParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt, MycatSchemaStatVisitor visitor)\n\t\t\tthrows SQLNonTransientException {\n\t\t// 对于lock tables table1 write, table2 read类型的多表锁语句，DruidParser只能解析出table1，\n\t\t// 由于多表锁在分布式场景处理逻辑繁琐，且应用场景较少，因此在此处对这种锁表语句进行拦截。\n\t\t// 多表锁的语句在语义上会有\",\"，这里以此为判断依据\n\t\tString sql = rrs.getStatement();\n\t\tsql = sql.replaceAll(\"\\n\", \" \").replaceAll(\"\\t\", \" \");","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/MyCATApache/Mycat-Server/blob/65f8d8beb752f935752f2a0eec0ab017facab9ef/src/main/java/io/mycat/route/parser/druid/impl/DruidLockTableParser.java#L21-L57","documentation":"After resolving the table config, the LOCK TABLES parser validates that each lock item's type is WRITE or READ. Any other MySQL lock type (e.g. LOW_PRIORITY WRITE, or multi-item statements with unusual lock types) is rejected with a SQLNonTransientException because Mycat cannot map it to a backend route.","triggerScenarios":"Executing `LOCK TABLES ... LOW_PRIORITY WRITE`, `... READ LOCAL`, or any lock type other than plain WRITE/READ against a Mycat-configured sharding table.","commonSituations":"Apps or dump tools emitting extended lock syntax (mysqldump uses `LOCK TABLES ... READ LOCAL`); ORM-generated session locking statements using priority modifiers; scripts written for standalone MySQL run unchanged through Mycat.","solutions":["Rewrite the statement to plain `LOCK TABLES tbl WRITE` or `LOCK TABLES tbl READ` (strip LOW_PRIORITY / READ LOCAL modifiers)","Strip or translate lock statements in the client/driver before they reach Mycat","Configure Mycat's ignoreUnknownCommand / SQL firewall or route locking statements to a backend directly"],"exampleFix":"-- before\nLOCK TABLES t_user READ LOCAL;\n-- after\nLOCK TABLES t_user READ;","handlingStrategy":"validation","validationCode":"String sql = sql.trim().toUpperCase();\nif (sql.startsWith(\"LOCK TABLES\") && (sql.contains(\"READ LOCAL\") || sql.contains(\"LOW_PRIORITY\"))) {\n    sql = sql.replace(\"READ LOCAL\", \"READ\").replace(\"LOW_PRIORITY \", \"\");\n}","typeGuard":null,"tryCatchPattern":"try { route(...); } catch (SQLNonTransientException e) { if (e.getMessage().contains(\"lock type must be\")) { rewritePlainLock(); } else throw e; }","preventionTips":["Use only LOCK TABLES ... READ/WRITE forms through Mycat","Configure mysqldump/backup tools to use --skip-lock-tables or lock via the backend","Normalize SQL in middleware before sending to Mycat","Test dump/backup tools against Mycat before production use"],"tags":["mysql","routing","lock-tables","unsupported-syntax"],"backgroundTag":"invalid-enum-value","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"}