公司使用cobar作为分库的中间件,最近要上对cobar的监控,从github上知道cobar本身是带了监控模块的,编译打包后发布到tomcat,修改好配置可以正常运行。后来不知怎么回事把日志级别调为debug了,然后就不停的抛异常,刚开始没意识是日志的问题,看异常信息:
Exception in thread "main" org.springframework.jdbc.UncategorizedSQLException: StatementCallback; uncategorized SQLException for SQL [show @@version]; SQL state [HY000]; error code [1003]; Unsupported statement; nested exception is java.sql.SQLException: Unsupported statement
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:407)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:458)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:466)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:474)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:479)
at com.alibaba.cobar.manager.SimpleDao.getVersion(SimpleDao.java:11)
at com.alibaba.cobar.manager.Main.main(Main.java:17)
Caused by: java.sql.SQLException: Unsupported statement
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1075)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3562)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3494)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1960)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2114)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2690)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2619)
at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1465)
at com.mysql.jdbc.SQLError.convertShowWarningsToSQLWarnings(SQLError.java:753)
at com.mysql.jdbc.SQLError.convertShowWarningsToSQLWarnings(SQLError.java:701)
at com.mysql.jdbc.StatementImpl.getWarnings(StatementImpl.java:2311)
at org.springframework.jdbc.core.JdbcTemplate.handleWarnings(JdbcTemplate.java:1216)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:397)
... 6 more
刚开始以为是连接的不是cobar监控的端口,但是在命令上运行都是没有问题,我直接使用jdbc连接取监控数据也没问题。折腾了半天之后,新建了一个项目没有配置log4j,居然可以运行了,这才怀疑是日志的问题,我重新配置了log4j,级别调成info没问题了,换成debug,还是抛出那个异常。这样诡异的问题只能看源码了。
比如执行show @@version命令(cobar监控支持的命令)时,调用JdbcTemplate的execute方法:
Connection conToUse = con;
if (this.nativeJdbcExtractor != null &&
this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
stmt = conToUse.createStatement();
applyStatementSettings(stmt);
Statement stmtToUse = stmt;
if (this.nativeJdbcExtractor != null) {
stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
}
Object result = action.doInStatement(stmtToUse);
handleWarnings(stmt);
return result;
调试进去之后看到执行到action.doInStatement还是正常的,也返回了结果,执行handleWarnings时抛出异常,看看handleWarnings方法:
protected void handleWarnings(Statement stmt) throws SQLException {
if (isIgnoreWarnings()) {
if (logger.isDebugEnabled()) {
SQLWarning warningToLog = stmt.getWarnings();
while (warningToLog != null) {
logger.debug("SQLWarning ignored: SQL state '" + warningToLog.getSQLState() + "', error code '" +
warningToLog.getErrorCode() + "', message [" + warningToLog.getMessage() + "]");
warningToLog = warningToLog.getNextWarning();
}
}
}
else {
handleWarnings(stmt.getWarnings());
}
}
难怪,原来设成debug之后,会调用stmt.getWarnings()方法,但是这个方法怎么会抛出异常的,下载了mysql driver的源码,有以下代码:
SQLWarning pendingWarningsFromServer = SQLError
.convertShowWarningsToSQLWarnings(this.connection);
而SQLError的convertShowWarningsToSQLWarnings方法中又调用了stmt.executeQuery("SHOW WARNINGS");
SHOW WARNINGS是mysql5.0之后的特性:官网解释如下:
SHOW WARNINGS is a diagnostic statement that displays information about the conditions (errors, warnings, and notes) resulting from executing a statement in the current session. Warnings are generated for DML statements such as INSERT, UPDATE, and LOAD DATA INFILE as well as DDL statements such as CREATE TABLE and ALTER TABLE.
即得到执行insert、update、load data infile以及建表和修改表等DDL语句返回的警告信息。这个语法mysql5.0之后支持,在命令行运行后没有报错,到了这儿事情已经明朗了,是cobar监控不支持该语法,所以抛出了Unsupported statement这个错误。
来源:oschina
链接:https://my.oschina.net/u/124730/blog/268371