🙌

ローカルだけ再現する「Illegal mix of collations」を追いかけたら JDBC ドライバ差し替えが犯人だった話

に公開

Docker 上の GlassFish + MySQL 5.7 環境で、mst_dictionary テーブルの文言取得 API を叩くと Illegal mix of collations が発生する事象に遭遇しました。クラウド上の共有開発環境では再現しないため「ローカル固有の環境差異」を中心に調査した際のメモです。


発生状況

  • エラー: java.sql.SQLException: Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8mb4_general_ci,COERCIBLE) for operation '='
  • 影響: 設備メンテ開始/終了など、mst_dictionary の一部キーを取得する API だけが失敗
  • 環境: Docker (MySQL 5.7, GlassFish) ※本番・他開発環境では再現せず
Exception [EclipseLink-4002]: DatabaseException
Internal Exception: java.sql.SQLException: Illegal mix of collations ...
Call: SELECT ... FROM mst_dictionary WHERE ((LANG_ID = ?) AND (DICT_KEY IN (?)))

当初の仮説と調査方針

  1. 照合順序の不一致
    MySQL 5.7 既定 (utf8_general_ci) と、Tool 側が utf8mb4_general_ci を投げている疑い。
  2. ダンプ/インポート時のキャラクタセット差異
    mysqldump、MySQL Workbench 8.0 などが utf8mb4 を混入させた可能性。
  3. セッション初期化 SQL の不足
    接続時の SET NAMES が適切に行われていないかもしれない。

→ テーブルの照合順序やサーバ変数を確認したところ、ほとんどが utf8_general_ci のまま。サーバ・スキーマは utf8 で統一済みだったため、SQL のパラメータ側が utf8mb4 になっている と考えました。

真の原因を特定

過去の Docker 検証で MySQL Connector/J を 8.0.30 に差し替え、GlassFish の domain.xml を変更した状態 が戻されていないことが判明しました。

  • mysql-connector-java-5.1.23-bin.jarmysql-connector-java-8.0.30.jar
  • domain.xml にも検証用の設定が残存

Connector/J 8.0 系はデフォルトで utf8mb4 を優先してパラメータを送信する設定があり、サーバ側テーブルが utf8_general_ci のままだと照合順序の衝突 (Error 1267) が発生します。

今回の API ルートではドライバ差し替えの影響を強く受け、特定キーの取得だけが失敗していました。

対応内容

  1. GlassFish のライブラリを 標準ドライバ (mysql-connector-java-5.1.23-bin.jar) に差し戻し
  2. domain.xml をリポジトリの正規状態へ戻す。
  3. 念のため MySQL サーバとテーブルの照合順序を utf8/utf8_general_ci で統一。
  4. mysqldump、MySQL Workbench なども --default-character-set=utf8 を徹底。

修正後は当該 API でエラーが再発しませんでした。

まとめ

  • 「照合順序エラー」は単にテーブル設定だけでなく、クライアントドライバの挙動 も疑うべき。
  • 検証目的で差し替えた構成は、作業完了後に必ず元へ戻す運用を徹底する。
  • MySQL 5.7 前提の環境では、utf8mysql-connector-java 5.1.x の組み合わせを維持することで予期せぬ照合順序差異を避けられる。

今後は検証用の変更を git diff などで確認しつつ、環境差異が残っていないかをチェックリスト化しておく予定です。

Discussion