sql >> Database >  >> RDS >> Mysql

utf8-gegevens zien er goed uit in mysql, maar zijn gebroken in rails

Wanneer een MySQL-client interageert met de server:

  1. de server ontvangt elke tekst alleen als een reeks bytes; de klant heeft hem eerder verteld hoe dergelijke tekst zou worden gecodeerd.

  2. als de server die tekst vervolgens in een tabel moet opslaan, moet hij deze transcoderen naar de codering van de relevante kolom (indien anders).

  3. als de client vervolgens dergelijke tekst wil ophalen, moet de server deze transcoderen naar de codering die door de client wordt verwacht.

Als de coderingen die door de client in stap 1 en 3 worden gebruikt, dezelfde zijn (wat meestal het geval is, vooral wanneer de client in beide gevallen dezelfde toepassing is), dan wordt het vaak onopgemerkt als de client een andere codering gebruikt dan hij zei dat het zou doen. Stel bijvoorbeeld dat de client MySQL vertelt dat het latin1 . zal gebruiken , maar verzendt feitelijk gegevens in utf8 :

  • De string 'Jazz–Man' wordt in UTF-8 naar de server gestuurd als 0x4a617a7ae280934d616e .

  • MySQL, die die bytes decodeert in Windows-1252, begrijpt dat ze de tekenreeks 'Jazz–Man' vertegenwoordigen .

  • Opslaan in een utf8 kolom, transcodeert MySQL de string naar zijn UTF-8-codering 0x4a617a7ac3a2e282ace2809c4d616e . Dit kan worden geverifieerd met behulp van SELECT HEX(name) FROM lessons WHERE id=79510 .

  • Wanneer de client de waarde ophaalt, denkt MySQL dat hij deze in latin1 wil hebben en dus transcodeert naar de Windows-1252-codering 0x4a617a7ae280934d616e .

  • Wanneer de client die bytes ontvangt, decodeert hij ze als UTF-8 en begrijpt daarom de tekenreeks als 'Jazz–Man' .

Conclusie :de klant heeft niet door dat er iets aan de hand is. Problemen worden alleen gedetecteerd wanneer een andere client (een die zijn UTF-8-verbinding niet verkeerd aangeeft als latin1 ) probeert de tabel te gebruiken. In uw geval gebeurde dit toen mysqldump een export van de gegevens kreeg; met behulp van de --default-character-set=latin1 --skip-set-charset opties dwongen mysqldump in feite om zich op dezelfde kapotte manier te gedragen als uw applicatie, dus het eindigde met correct gecodeerde gegevens.

Om uw probleem in de toekomst op te lossen, moet u:

  1. Configureer uw toepassing zodat deze de MySQL-verbindingstekenset correct instelt (bijv. stel encoding: utf8 in in config/database.yml voor rails);

  2. Hercodeer de gegevens in uw database, b.v. UPDATE lessons SET name = BINARY CONVERT(name USING latin1) (merk op dat dit moet worden gedaan voor elke verkeerd gecodeerde tekstkolom).

Houd er ook rekening mee dat je deze twee acties waarschijnlijk atomair wilt uitvoeren, wat misschien wat nadenken vereist.



  1. MySQL-tijdzone-query

  2. Roep een opgeslagen procedure aan met een andere in Oracle

  3. Hoe het aantal getroffen rijen te krijgen, tijdens het uitvoeren van een MySQL-query vanuit bash?

  4. Hoe UUID() werkt in MariaDB