概要
サロゲートペア文字を入力すべく、
AzureのMySQLで使用可能な文字コードをutf8からutf8mb4に変更をしました。
下記3つを設定する必要がありました。
MySQL側の設定
JDBC側の設定
Connector/J のバージョン
MySQL側の設定
サーバパラメータの設定
// サーバの文字コードを設定
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
// 接続レベルの文字コードを設定
init_connect=
SET character_set_client=utf8mb4;SET character_set_connection=utf8mb4;SET character_set_results=utf8mb4;SET character_set_database=utf8mb4;
設定後、mysqlサーバの再起動
テーブルの設定変更
ALTER TABLE {tableName} CONVERT TO CHARACTER SET utf8mb4;
JDBC側の設定
接続文字列
接続文字列には、characterEncoding=utf8を設定する必要があります。
Azureのサポートの方に下記の回答をいただきました。
ゲートウェイは共用のコンポーネントのため、お客様毎に個別の文字コードを設定することができません。
ゲートウェイと Connector/J 間でハンドシェイクを行う際に、
サーバーサイド(実際はゲートウェイ)で utf8 が設定されていると Connector/J が認識してしまい、Connector/J が SET NAME utf8 を実行してしまっておりました。
よって、サーバーサイドだけでなく、クライアントサイド(Connector/J サイド)でもutf8mb4 を使用することを明示的に指定する必要があり、接続文字列で characterEncoding=utf8 を指定する必要がございます。
回答いただいた通り、characterEncoding=utf8を指定しないとAzureのMySQLでは正常にutf8mb4にならない模様です。
Connector/J のバージョン
Connector/J 5.1.47 以降のバージョンである必要があります。
Connector/J 5.1.47 以前のバージョンを指定すると、characterEncoding=utf8を指定したとしても、characterEncoding=utf8mb3が利用されてしまう問題があるようです。
https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-charsets.html
JDBC経由でAzure MySQLに接続
MySQL側の設定、JDBC側の設定、Connector/J のバージョンを変更したら、
JDBC経由で下記を実行して、正しく文字コードが設定されて接続できているのかを確認します
SELECT * FROM performance_schema.session_variables WHERE variable_name LIKE 'character_set%';
テストコード
テストコードはこちらの記事を引用にさせていただいております。(ありがとうございます!)
package jp.co.tdc.asp.core.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Test {
public static void main( String args[] ) throws Exception {
/*接続するデータベース名*/
String databasename = "XXXXXXXXXXXXXXXXXXXX";
/*データベースの接続に用いるユーザ名*/
String user = "XXXXXXXXXXXXXXXXXXXX";
/*データベースの接続に用いるユーザのパスワードを指定している*/
String password = "XXXXXXXXXXXXXXXXXXXX";
/*データベースをあらわすURLを設定している*/
String url = "jdbc:mysql://XXXXXXXXXXXXXXXXXXXX.mysql.database.azure.com/" + databasename + "?characterEncoding=utf8";
/*接続を表すConnectionオブジェクトを初期化*/
Connection con = null;
try{
/*クラスローダによりJDBCドライバを読み込んでいることを示している。
引数は、データベースにアクセスするためのJDBCドライバのクラス名である。*/
Class.forName( "com.mysql.jdbc.Driver" );
/*DriverManagerクラスのgetConnectionメソッドを使ってデータベースに接続する。*/
con = DriverManager.getConnection( url, user, password );
System.out.println( "Connected...." );
/*データベースの接続後に、sql文をデータベースに直接渡すのではなく、
sqlコンテナの役割を果たすオブジェクトに渡すためのStatementオブジェクトを作成する。*/
Statement st = con.createStatement();
/*SQL文を作成する*/
String sqlStr = "SELECT * FROM performance_schema.session_variables WHERE variable_name LIKE 'character_set%';";
/*SQL文を実行した結果セットをResultSetオブジェクトに格納している*/
ResultSet result = st.executeQuery( sqlStr );
/*クエリ結果を1レコードずつ出力していく*/
while( result.next() )
{
/*getString()メソッドは、引数に指定されたフィールド名(列)の値をStringとして取得する*/
String str1 = result.getString( "VARIABLE_NAME" );
String str2 = result.getString( "VARIABLE_VALUE" );
System.out.println( str1 + "=" + str2 );
}
/*ResultSetオブジェクトを閉じる*/
result.close();
/*Statementオブジェクトを閉じる*/
st.close();
/*Connectionオブジェクトを閉じる*/
con.close();
}
catch( SQLException e ){
/*エラーメッセージ出力*/
System.out.println( "Connection Failed. : " + e.toString() );
/*例外を投げちゃうぞ*/
throw new Exception();
}catch (ClassNotFoundException e){
/*エラーメッセージ出力*/
System.out.println("ドライバを読み込めませんでした " + e);
}
finally{
try{
if( con != null ){
con.close();
}
}
catch(Exception e){
/*エラーメッセージ出力*/
System.out.println( "Exception2! :" + e.toString() );
/*例外を投げちゃうぞ*/
throw new Exception();
}
}
}
}
テストコードの結果が下記のようになれば成功です。
Connected....
character_set_client=utf8mb4
character_set_connection=utf8mb4
character_set_database=utf8mb4
character_set_filesystem=binary
character_set_results=
character_set_server=utf8mb4
character_set_system=utf8
character_sets_dir=c:\mysql\share\charsets\
サロゲートペア文字の入力が可能になっているはずです。
おわり
接続の際にうまくいかず、サポートの方に対応してもらったので、備忘のためにメモ