質問: アプリ 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 だった。
回答: Javaでサロゲートペアをサポートしようとするとそれぞれのキャラクタをコードポイントに変換する必要があります。 ``` 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; } ``` 上記でコードポイントに変換した配列が返ってきますので、区切り文字で区切って格納すればどうでしょうか? 読みだすときは`split`で配列にしてコードポイントから文字列に変換すればいいかと...... ``` public static String toString(int[] codePoints) { return new String(codePoints, 0, codePoints.length); } ``` ......と、コードポイント変換のコードを添付しましたが、 自分は上位下位に分かれてくれるので普段ライブラリを使って一旦JSON化してます。