Description:
When network fails down, unexpected exceptions will be thrown during the statement-execute phase:
Using PreparedStatement, throw a StatementIsClosedException, but it should be a CommunicationsException;
Using a Statement, throw an NPE, but it should be a CommunicationsException;
Under the above conditions, the thrown exception does not directly reflect the root cause of the problem,
which can confuse those who see the exception information. The main reason is that unexpected NPEs occur within the connector/J during handling the socket-timeout;
How to repeat:
// copy below codes to any class
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (Exception e) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (Exception t) {
throw new RuntimeException(t);
}
}
}
public static final String MYSQL_URL_FORMAT = "jdbc:mysql://%s/%s?useSSL=false&characterEncoding=UTF-8";
public void mysql8SocketTimeoutTest() throws SQLException {
String statementType = "preparedStatement";
int queryTimeout = 2;
try(Connection connection = getConnection()) {
if (statementType.equalsIgnoreCase("preparedStatement")) {
try (PreparedStatement statement = connection.prepareStatement("select * from dalservicetable limit 10")) {
statement.setQueryTimeout(queryTimeout);
statement.execute();
// Omit for Processing of ResultSet
} catch (Exception e) {
e.printStackTrace();
}
} else {
try(Statement statement = connection.createStatement()) {
statement.setQueryTimeout(queryTimeout);
statement.executeQuery("select * from dalservicetable limit 10");
// Omit for Processing of ResultSet
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private Connection getConnection() throws SQLException {
return DriverManager.getConnection(String.format(Constants.MYSQL_URL_FORMAT, "ip:port", "dbname"), "uid", "pwd");
}
Suggested fix:
in src/main/core-impl/java/com/mysql/cj/AbstractQuery.java(228)
this.session.getCancelTimer().purge();
there should be a null check before purge the cancelTimer;
suggest:
if (this.session != null && this.session.getCancelTimer() != null)
this.session.getCancelTimer().purge();