システム環境:
オペレーティングシステム: MAC OS 10.11.6
MySQL:サーバーバージョン:5.6.21 MySQL Community Server (GPL)
Navicat for MySQL: バージョン 9.3.1 - 標準
1. 問題の発見
クライアントでユーザー登録を実行すると、ユーザー名に絵文字が含まれます。登録が完了すると、APP クライアントと Web ページのフロントエンドに絵文字記号を含むユーザーのニックネームが正常に表示され、データが保存されていることを示します。 Navicat で mysql クライアントで「ユーザーテーブル tb_user」を開くと、表示される「ユーザーニックネーム Nick_name」が文字化けするのはなぜですか?
mysql> select nick_name from tb_user where id = 91;
+---------------+
| nick_name |
+---------------+
| 涛声依旧? |
+---------------+
1 rows in set (0.03 sec)
上記のように、クエリ結果 [ Taosheng is Still? ] のユーザーのニックネームに疑問符が表示されますが、これは絵文字であるはずです。このフィールドの文字セットは 4 バイトの絵文字記号と互換性のある utf8mb4 に設定されているため、データの保存には問題ありません。最初の推測は、データベース クエリからデータを取得した後、クライアントにデータを返すプロセスに問題があるということです。!
2. 問題分析
MySQL は C/S アーキテクチャを使用しているため、サーバーとクライアント (MySQL に付属のクライアント、Navicat for MySQL など) があり、その 2 つの端が異なるホストに分散されている場合、通常は 2 つの端が同じになります。 TCP/IP またはその他のプロトコルを渡す必要がある場合は、接続を確立し、通信またはデータ転送を可能にします。HTTP プロトコルと似ていますが、HTTP がリクエストを開始すると、クライアントの「情報本体」が使用する文字セットがヘッダーに付加されます。同様に、MySQL の両端も通信に使用する文字セットを事前に通信する必要があり、そうでないとサーバーはクライアントが何を望んでいるのかを知りませんし、クライアントはサーバーが何を与えるのかを知りません。
MySQL は、クライアントとサーバー間の通信を支援するために、 3 つの文字セット変数、 character_set_client、character_set_connection、およびcharacter_set_resultsを提供します。
- Character_set_client : サーバーは、リクエストのバイト シーケンス (例: SQL クエリ ステートメント) を、character_set_client 文字セットでエンコードされたバイト シーケンスとして処理します。クライアントによって要求された mysql ステートメントのエンコーディングが UTF8 で、character_set_client の値が GBK の場合、サーバーは GBK エンコーディングに従ってそれを受信します。2 つのエンコーディングは矛盾しており、nick_name = "A" のリクエストはwhere Nick_name = "B" と誤ってみなされた場合、当然返されるデータが正しくないか、クエリ データが空です。
- Character_set_connection : データベースに接続するときの文字セット。
- Character_set_results : データベースがクライアントにデータを返すために使用する文字セット。
一般に、文字化けが表示されるのは、文字セット変数の設定に関連していることが多いです。文字セットがデータベースに格納されているデータに関連していることはわかっていますが、クライアント (Navicat) とサーバー間の対話も影響を受けます。文字セット。クライアントによって開始されたクエリ ステートメントとクライアントに返される結果は両方とも文字セット (エンコーディング) に関連しています。
上で述べたように、APP クライアントと Web ページのフロントエンドは両方とも正常に表示され、テーブル フィールドの文字セット設定も正しく表示されます。これは、データ ストレージに問題がないことを示していますが、問題はおそらく Nacatcat クライアントと MySQL サーバー間の対話にあり、つまり、上記の 3 つの文字セット変数に関係があると考えられます。
次に、Navicat クライアントでコンソール ウィンドウを開いて、これら 3 つの変数の値をクエリします。
show variables like "character_set%";
結果:
これら 3 つの変数の文字セットはすべて utf8 であり、mysql の utf8 文字セットは実際の utf8 ではなく、去勢されたバージョンであり、最長のものはわずか 3 バイトであることがわかります。utf8 文字セットは簡体字中国語の保存には問題ありませんが、4 バイトの絵文字を保存するには不十分です。
上記のクエリ結果から判断すると、正しい結果が返されており(形式が間違っているだけです)、クライアントとサーバーはリクエストの送受信プロセス中に文字セットの不一致によるエラーを引き起こしていません。そのため、character_set_client の文字 セット変数の値は問題ありません。
Character_set_clientの疑いが 除外され たら、 character_set_results = utf8を確認します 。 これは、クエリ結果がこの文字セットに従ってエンコードされることを意味します。クエリ フィールド (nick_name) には、データベース内の ut8mb4 文字セットに保存されている絵文字が含まれています。読み取り後、utf8 文字に変換され、Navicat クライアントに送信されます。2 つの文字セットの文字エンコーディングが一致していないため、 , Navicat クライアント側の表示が文字化けしてしまいます。
問題が見つかったので、対処は簡単なので、これら 3 つの変数 (実際には、character_set_results を設定するだけです) を、絵文字表現と互換性のある文字セット utf8mb4 に設定します。
# 等效于将三个变量同时设置为utf8mb4字符集
set names utf8mb4
# 单独设置一个变量
set character_set_results=utf8mb4;
変更後に再度クエリを実行すると、この絵文字表現が正常に表示されることがわかります。
3. 問題解決
注: 上記の 3 つの文字セット変数はスコープによって制限されており、それらはすべて同じセッション スコープに属します。コンソール ウィンドウを開くと、クライアントとサーバーの間に新しい接続を作成するのと同じです。値これら 3 つの文字セット変数のうち、現在のセッションのスコープ内でのみ有効です。新しいウィンドウまたは接続を再度開くと、以前の文字セット (UTF8) 設定が復元されます。
Navicat クライアントがデータ テーブルを開いてデータを表示する操作は、コンソール ウィンドウでクエリ ステートメントを実行するのと同じです。テーブル内のデータはクエリの後に返されるデータであるため、上記の 3 つとも直接関連しています。文字セット変数。では、Navicat クライアントはどのようにしてデータ テーブルを開いて、常に通常の絵文字表現を表示できるのでしょうか?
実際、Navicat for Mysql クライアントにはデータベースの「接続プロパティ」設定パネルがあり、そこで「クライアント文字セット」を設定できます。これは、MySQL インストール ディレクトリ my.conf | my.ini での設定と同じです。クライアントとサーバーが接続するたびに、ここでの設定に従って上記の 3 つの文字セット変数を事前に設定します。
4. 結論
これは絵文字が文字化けする場面を分析した紹介ですが、この考え方を参考に、どのクライアントでも同様の「文字化け」が起きている状況、つまり「保存」と「送信・送信」から分析することが可能です。キャラクターのインタラクション」を2つの角度から分析することで、必ず問題の根源を見つけ出します。
上記で「文字セット」 に関する用語がいくつか出てきましたが、実は MySQL の不可解な「文字化け」もこれと密接に関係しています。したがって、MySQL 文字セットを明確かつ徹底的に理解する必要があります。MySQL 文字セットを本当に理解したい場合は、著者の別の記事を参照してください。