18474


アプリ JavaDataInputStream JDBC-MariaDB MariaDB  
の順で絵文字を格納したいのですが、格納される文字が ????? になります。（絵文字部分だけ）  
全ての絵文字がそうなるわけではなく、サロゲートペアのものがそうなります。  
もちろん通常の文字だけなら普通に格納されます。

データベースのテーブルは utf8mb4 で、カラムも utf8mb4 であることを確認しています。  
useUnicode=true&characterEncoding=utf8mb4 をつけてコネクションを取得しています。

試しに set names utf8mb4 も試しましたがこれもダメでした。

何をしても ??? で保存されてしまうのですが何処が行けないのでしょうか？

追記  
やはり解決できません

□絶対だと分かっていること  
・テーブルは正常にutf8mb4である  
カラム単位でチェック済み  
これをする前は例外が発生していたが、これをしてから例外は発生しなくなった。  
そもそも、コネクションを通さなければ格納できる。

・コネクションは1.2.3（mariadb java）  
サロゲートペアが？になるバグは修正されているとここでの解答してくださった方により判明

・アプリ ←→ サーバー の通信はうまく行われている。  
DBに格納しないでそのままエコーすると正常に表示される。

・悪いのは MariaDB コネクション  
ターミナルなどではサロゲートペアでも普通に格納できる。  
また、PrepareStatementを使用している点が怪しい？  
（？をエスケープして置換してくれるやつ）

・コネクションには以下を指定（うるおぼえ）  
useUtf=tru charset=utf8mb4

・MariaDBにデータが届いた時点で文字化けではなくそもそも ？ という文字に置き換わっていると思われる。  
やはり、コネクションでの変換が原因？

要するに悪いのは絶対 MariaDB Connection Java だと思われるのですが、とても困っています。

追記追記  
対応できました！！！！！！！！！！！！  
原因 SQLの関数 ストアドプロシージャ の client_character 的なのが utf-8 だった。


CC BY-SA 4.0
2015-10-01T05:36:41.297
17134
2019-09-08T02:10:24.750
2019-09-08T02:10:24.750
76
10346
question
java android mariadb jdbc
絵文字を格納したいが　?????　になる


? になるのはJava側の問題のような気がします。  
[こちら](http://qiita.com/PGMY/items/4529494b7205ae0b2672)の記事によると古いJDBCドライバの場合、????
になるそうですのでJDBCドライバのバージョンを変えてみるのはどうでしょう。


CC BY-SA 3.0
2015-10-01T07:15:57.960
17141
2015-10-01T07:15:57.960
5008
17134
answer


Javaでサロゲートペアをサポートしようとするとそれぞれのキャラクタをコードポイントに変換する必要があります。

[code]

    public static int[] toCodePoints(String str) {
        int length = str.codePointCount(0, str.length());
        int[] codePoints = new int[length];
        int j = 0;
        for (int i = 0; i < str.length(); i = str.offsetByCodePoints(i, 1)) {
            codePoints[j++] = str.codePointAt(i);
        }
        return codePoints;
    }
    
[/code]

上記でコードポイントに変換した配列が返ってきますので、区切り文字で区切って格納すればどうでしょうか？  
読みだすときは`split`で配列にしてコードポイントから文字列に変換すればいいかと……

[code]

    public static String toString(int[] codePoints) {
        return new String(codePoints, 0, codePoints.length);
    }
    
[/code]

……と、コードポイント変換のコードを添付しましたが、  
自分は上位下位に分かれてくれるので普段ライブラリを使って一旦JSON化してます。


CC BY-SA 3.0
2015-10-01T08:47:32.363
17142
2015-10-01T08:47:32.363
7676
17134
answer


以下は回答ではなく、こちらの環境で試してみた結果です。

**実行環境**

  * OS: Ubuntu Linux 15.04
  * MariaDB: 10.0.20
  * Java: Java(TM) SE Runtime Environment(build 1.9.0-ea-b81)
  * MariaDB Connector/J: 1.3.0-beta2

以下のサンプルプログラムを実行してみました。MariaDB Connector/J に含まれているサンプルプログラムでは絵文字を `byte[]`
にしていますので、それも試しています。

[code]

    PreparedStatement ps =
      connection.prepareStatement("INSERT INTO emojiTest (id, field) VALUES (?, ?)");
    
    ps.setInt(1, 1);
    ps.setString(2, "");
    ps.execute();
    
    byte[] emoji = new byte[]{(byte) 0xF0, (byte) 0x9F, (byte) 0x98, (byte) 0x84};
    ps.setInt(1, 2);
    ps.setBytes(2, emoji);
    ps.execute();
    
[/code]

MariaDB 側で表示してみると、どちらも正常に表示されています。

[code]

    MariaDB [test]> select * from emojiTest;
    +------+-------+
    | id   | field |
    +------+-------+
    |    1 |     |
    |    2 |     |
    +------+-------+
    
[/code]

これは関係があるのかどうか不明ですが、MariaDB の config ファイルに、`skip-character-set-client-
handshake` を追加しています。

[code]

    #
    # * Character sets
    #
    # Default is Latin1, if you need UTF-8 set all this (also in client section)
    #
    skip-character-set-client-handshake
    character-set-server  = utf8mb4
    collation-server      = utf8mb4_unicode_ci
    character_set_server  = utf8mb4
    collation_server      = utf8mb4_unicode_ci
    
[/code]

`skip-character-set-client-handshake` を指定しないと文字化けを起こしますが、`set names utf8mb4;`
を実行すれば良いだけの話ですので、あまり関係はないのかもしれません。


CC BY-SA 3.0
2015-11-02T12:13:51.987
18328
2015-11-02T12:13:51.987
17134
answer


自己解決

## 原因

ストアドプロシージャ（関数など）の `client_` が `utf-8` のままだった。  
まさか、 ストアドプロシージャ にも文字コードの設定があるとは気づかず、とてつもない時間を解決に要してしまいました。

ちなみにですが、私の実行できた設定は以下になります。  
（やはり設定トラブルも多いようなので）

## 確認方法

[code]

    show create PROCEDURE xxxxxxx;
    
[/code]

`character_set_client` が `utf-8` だった  
また、ほかに続くのも `utf8_general_ci` だった。

* * *

## /etc/my.cnf（必要な部分のみ）

[code]

    collation_server=utf8mb4_unicode_ci
    character-set-server=utf8mb4
    [mysql]
    default_character_set=utf8mb4
    [client]
    default-character-set=utf8mb4
    
[/code]

* * *

## コネクション

[code]

    DriverManager.getConnection("jdbc:mariadb://localhost/" + D.DataBaseName + "?user=" + D.DataBaseUser + "&password=" + D.DataBasePass + "&autoReconnect=true&useUnicode=true&characterEncoding=utf8mb4&connectionCollation=utf8mb4_general_ci");
    
[/code]

`set names` などの発行はなし。  
`skip-character-set-client-handshake` も使用していない

* * *

## データベース

テーブルの文字コードは `utf8mb4`  
テーブルのカラム単位でも文字コード指定ができるみたいなのでそれも同じく `utf8mb4`


CC BY-SA 4.0
2015-11-06T10:38:18.310
18474
2019-09-07T21:08:41.073
2019-09-07T21:08:41.073
32986
10346
17134
answer