2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Azure Database for MySQL(5.7)にJDBC経由で接続し文字コードutf8mb4を使う

Posted at

概要

サロゲートペア文字を入力すべく、
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 を指定する必要がございます。

image1

回答いただいた通り、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%';

テストコード

テストコードはこちらの記事を引用にさせていただいております。(ありがとうございます!)

Test.java
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();
        }
    }
}
}

テストコードの結果が下記のようになれば成功です。

result
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\

サロゲートペア文字の入力が可能になっているはずです。

おわり

接続の際にうまくいかず、サポートの方に対応してもらったので、備忘のためにメモ

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?