【トラブル】【Java】MySQLのJDBCドライバを v5.1.X から v8.0.X に上げた時のトラブル

  【1】MySQLJDBCドライバを上げたらエラー「The server time zone value」になる

  現象詳細

MySQLJDBCドライバを v5.1.46 から v8.0.11 にあげたとこと、
以下の「エラー内容」になる

  build.gradle

修正前 (現象発生なし)
dependencies {    
    // MySQL
    compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.46'
}
修正後 (現象発生あり)
dependencies {    
    // MySQL
    compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.11'
}

  エラー内容

java.sql.SQLException: The server time zone value '???? (?W????)' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:127)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:95)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:87)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:61)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:71)
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:76)
	at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:862)
	at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:444)
	at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:230)
	at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:226)
	at java.sql.DriverManager.getConnection(Unknown Source)
	at java.sql.DriverManager.getConnection(Unknown Source)
	at com.sample.db.SelectDemo.main(SelectDemo.java:15)
Caused by: com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value '???? (?W????)' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
	at java.lang.reflect.Constructor.newInstance(Unknown Source)
	at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:59)
	at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:83)
	at com.mysql.cj.util.TimeUtil.getCanonicalTimezone(TimeUtil.java:128)
	at com.mysql.cj.protocol.a.NativeProtocol.configureTimezone(NativeProtocol.java:2201)
	at com.mysql.cj.protocol.a.NativeProtocol.initServerSession(NativeProtocol.java:2225)
	at com.mysql.cj.jdbc.ConnectionImpl.initializePropsFromServer(ConnectionImpl.java:1391)
	at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:993)
	at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:852)
	... 6 more

  サンプル

修正前
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class SelectDemo {

  public static void main(String[] args) throws ClassNotFoundException {
    Class.forName("com.mysql.jdbc.Driver");

    try (
        Connection connection = DriverManager.getConnection(
            "jdbc:mysql://localhost:3306/sampledb", "root", "password");
        PreparedStatement preparedStatement = connection
            .prepareStatement("SELECT * FROM person");) {
      ResultSet resultSet = preparedStatement.executeQuery();
      while (resultSet.next()) {
        System.out.println(String.format("id=%s, name=%s",
            resultSet.getString("id"), resultSet.getString("name")));
      }
    } catch (SQLException ex) {
      ex.printStackTrace();
    }
  }
}

  解決案

 * 「serverTimezone」を指定する
  => 「serverTimezone=JST」みたいな。

  サンプル

修正後
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class SelectDemo {

  public static void main(String[] args) throws ClassNotFoundException {
    Class.forName("com.mysql.jdbc.Driver");

    try (
        Connection connection = DriverManager.getConnection(
            "jdbc:mysql://localhost:3306/sampledb?serverTimezone=JST", "root", "password"); // ★ここ★
        PreparedStatement preparedStatement = connection
            .prepareStatement("SELECT * FROM person");) {
      ResultSet resultSet = preparedStatement.executeQuery();
      while (resultSet.next()) {
        System.out.println(String.format("id=%s, name=%s",
            resultSet.getString("id"), resultSet.getString("name")));
      }
    } catch (SQLException ex) {
      ex.printStackTrace();
    }
  }
}

  参考文献

https://www.nakamuri.info/mw/index.php/Mysql-connector-java_%E3%81%AE%E3%83%90%E3%82%B0%E3%81%A7_Java%E3%81%8B%E3%82%89MySQL%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84

 

  【2】 MySQLJDBCドライバを上げたらエラー「class `com.mysql.jdbc.Driver'. This is deprecated.」って言われる

  ログ内容

Loading class `com.mysql.jdbc.Driver'.
This is deprecated.
The new driver class is `com.mysql.cj.jdbc.Driver'.
The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

  原因

英語読めばわかるが...
Class.forName("com.mysql.jdbc.Driver");
の指定が古いらしい。

  解決案

[1] Class.forName("com.mysql.cj.jdbc.Driver"); にする
又は
[2] Class.forName("com.mysql.jdbc.Driver"); の行を消す(自動的にロードしてくれるらしいので)

 

  関連記事

  JDBC ドライバのunregister 絡みのトラブル

https://blogs.yahoo.co.jp/dk521123/37476585.html