MySQLクライアントがサーバーと対話する場合:
-
サーバーは、テキストを単にバイトの文字列として受信します。クライアントは、そのようなテキストがどのようにエンコードされるかを以前に伝えているでしょう。
-
サーバーがそのテキストをテーブルに格納する必要がある場合は、関連する列のエンコーディングにトランスコードする必要があります(異なる場合)。
-
その後、クライアントがそのようなテキストを取得したい場合、サーバーはそれをクライアントが期待するエンコーディングにトランスコードする必要があります。
手順1と3でクライアントが使用したエンコーディングが同じの場合 (これは通常、特に両方の場合のクライアントが同じアプリケーションである場合に当てはまります)、クライアントがそれが言ったもの以外のエンコーディングを使用している場合、それはしばしば見過ごされます。たとえば、クライアントがMySQLにlatin1
を使用するように指示したとします。 、ただし実際にはutf8
でデータを送信します :
-
文字列
'Jazz–Man'
0x4a617a7ae280934d616e
としてUTF-8でサーバーに送信されます 。 -
MySQLは、Windows-1252でこれらのバイトをデコードし、文字列
'Jazz–Man'
を表すと理解します。 。 -
utf8
に保存するには 列、MySQLは文字列をUTF-8エンコーディングにトランスコードします0x4a617a7ac3a2e282ace2809c4d616e
。これは、SELECT HEX(name) FROM lessons WHERE id=79510
を使用して確認できます。 。 -
クライアントが値を取得すると、MySQLは
latin1
に値が必要であると判断します。 したがって、Windows-1252エンコーディング0x4a617a7ae280934d616e
にトランスコードします。 。 -
クライアントはそれらのバイトを受信すると、それらをUTF-8としてデコードするため、文字列が
'Jazz–Man'
であると理解します。 。
結論 :クライアントは何かが間違っていることに気づいていません。問題が検出されるのは、別のクライアント(UTF-8接続をlatin1
と誤って記述していないクライアント)の場合のみです。 )テーブルを使用しようとします。あなたの場合、これはmysqldumpがデータのエクスポートを取得したときに発生しました。 --default-character-set=latin1 --skip-set-charset
を使用する オプションを使用すると、mysqldumpはアプリケーションと同じように壊れた方法で動作するようになり、正しくエンコードされたデータになりました。
今後問題を解決するには、次のことを行う必要があります。
-
MySQL接続文字セットを正しく設定するようにアプリケーションを構成します(例:set
encoding: utf8
config/database.yml
内 Railsの場合); -
データベース内のデータを再コーディングします。例:
UPDATE lessons SET name = BINARY CONVERT(name USING latin1)
(これは、誤ってエンコードされたすべてのテキスト列に対して実行する必要があることに注意してください)。
また、これら2つのアクションをアトミックに実行することをお勧めしますが、これには多少の考慮が必要になる場合があります。