sql >> Database teknologi >  >> RDS >> Mysql

utf8-data ser fint ud i mysql, men er brudt i skinner

Når en MySQL-klient interagerer med serveren:

  1. serveren modtager enhver tekst blot som en streng af bytes; klienten vil tidligere have fortalt det, hvordan sådan tekst ville blive kodet.

  2. hvis serveren derefter skal gemme denne tekst i en tabel, skal den omkode den til kodningen af ​​den relevante kolonne (hvis forskellig).

  3. hvis klienten efterfølgende ønsker at hente sådan tekst, skal serveren omkode den til den kodning, som klienten forventer.

Hvis kodningerne brugt af klienten i trin 1 og 3 er samme (hvilket normalt er tilfældet, især når klienten i begge tilfælde er den samme applikation), så går det ofte ubemærket hen, hvis klienten bruger en anden kodning end den, den sagde, den ville. Antag for eksempel, at klienten fortæller MySQL, at den vil bruge latin1 , men sender faktisk data i utf8 :

  • Strengen 'Jazz–Man' sendes til serveren i UTF-8 som 0x4a617a7ae280934d616e .

  • MySQL, der afkoder disse bytes i Windows-1252, forstår dem til at repræsentere strengen 'Jazz–Man' .

  • For at gemme i en utf8 kolonne, omkoder MySQL strengen til dens UTF-8-kodning 0x4a617a7ac3a2e282ace2809c4d616e . Dette kan verificeres ved at bruge SELECT HEX(name) FROM lessons WHERE id=79510 .

  • Når klienten henter værdien, tror MySQL, at den vil have den i latin1 og så omkoder til Windows-1252-kodningen 0x4a617a7ae280934d616e .

  • Når klienten modtager disse bytes, afkoder den dem som UTF-8 og forstår derfor, at strengen er 'Jazz–Man' .

Konklusion :Klienten indser ikke, at der er noget galt. Problemer opdages kun, når en anden klient (en, der ikke angiver sin UTF-8-forbindelse forkert som latin1 ) forsøger at bruge tabellen. I dit tilfælde skete dette, da mysqldump opnåede en eksport af dataene; ved hjælp af --default-character-set=latin1 --skip-set-charset muligheder tvang mysqldump til at opføre sig på samme ødelagte måde som din applikation, så det endte med korrekt kodede data.

For at løse dit problem fremover skal du:

  1. Konfigurer din applikation, så den sætter sit MySQL-forbindelsestegnsæt korrekt (f.eks. sæt encoding: utf8 i config/database.yml for skinner);

  2. Omkode dataene i din database, f.eks. UPDATE lessons SET name = BINARY CONVERT(name USING latin1) (bemærk, at dette skal gøres for hver fejlkodet tekstkolonne).

Bemærk også, at du sandsynligvis vil udføre disse to handlinger atomært, hvilket kan kræve lidt eftertanke.



  1. serverens tidszoneværdi 'CDT' er ikke genkendt eller repræsenterer mere end én tidszone

  2. Hvorfor returnerer PHP crypt()-funktionen det samme for to forskellige strenge?

  3. Får fejl ORA-00909:ugyldigt antal argumenter

  4. Hvordan får jeg kategorien på første niveau til kun at blive vist én gang?