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

【1】「SEVERE: A web application registered the JDBC driver...」が表示される

 * Tomcatのログを見たら、Tomcat終了時に以下の「エラー内容」が表示された

エラー内容

SEVERE: A web application registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.

発生環境

 * OS : CentOS7
 * Tomcat : Tomcat8.5
 * Java :JDK1.8

解決案

 * システム終了後(※)に、以下の「サンプル」の処理(DriverManager.deregisterDriver())を行う
サンプル
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
    Driver driver = drivers.nextElement();
    try {
        DriverManager.deregisterDriver(driver);
        System.out.println(String.format("deregistering jdbc driver: %s", driver));
    } catch (SQLException ex) {
        System.out.println(String.format("Error deregistering driver %s", driver));
        ex.printStackTrace();
    }

}

※補足:システム終了後について

Tomcatであれば、ServletContextListener.contextDestroyed 内で行う。
Webサービスのシステム終了のイベントについては、以下の関連記事を参照のこと。
JAX-WS / Metro
https://blogs.yahoo.co.jp/dk521123/36238319.html
Axis2
https://blogs.yahoo.co.jp/dk521123/34600183.html

参考文献

https://stackoverflow.com/questions/3320400/to-prevent-a-memory-leak-the-jdbc-driver-has-been-forcibly-unregistered
http://d.hatena.ne.jp/muimy/20100918/1284812424

【2】「SQLException: No suitable driver found for...」が表示される

 * 【1】とは、別のシステムの単体試験時に、以下の「エラー内容」が表示された
 * 単体テストクラスには、3つのテストメソッドがあり、結果は以下の通り。
  + 1つ目は、問題なし
  + 2・3つ目のメソッドは、以下の「エラー内容」
 * ネットにある「JDBCドライバがない」「Class.forName()を呼び出す」「DBのURLの指定が誤っている」は
   調査した結果、問題なかった(仮にこれらが原因の場合、1つのメソッドが問題なかった説明ができない)
 ~~~~~~~
  // ダメだった
  @Before
  public void setUp() throws Exception {
      Class.forName("com.mysql.jdbc.Driver");
  }
 ~~~~~~~

エラー内容

java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/dbname

発生環境

 * OS : CentOS7
 * Java :JDK1.8
 * JUnit : JUnit4

原因

 * 【1】の「解決案」のコードを1つ目の最後に呼び出され、
    以降の単体試験に影響してしまっていた。

解決案

 * JUnitの場合、@AfterClassのタイミングで、【1】の「解決案」のコードを呼び出すようにする
 ~~~~~~~
  @AfterClass
  public static void tearDownAfterClass() throws Exception {
     // このタイミングで、【1】の「解決案」のコードを呼び出すようにする
  }
 ~~~~~~~

 => 【後日談】JUnitを一気に実行すると、エラーになるのでJUnitに関しては呼び出さないのも手。

関連記事

MySQLJDBCドライバを v5.1.X から v8.0.X に上げたらエラー「The server time zone value」になる

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