sql >> Databasteknik >  >> RDS >> Mysql

utf8-data ser bra ut i mysql men är trasig i skenor

När en MySQL-klient interagerar med servern:

  1. servern tar emot vilken text som helst bara som en sträng av bytes; klienten har tidigare berättat hur sådan text skulle kodas.

  2. om servern sedan måste lagra den texten i en tabell, måste den omkoda den till kodningen för den relevanta kolumnen (om den är annorlunda).

  3. om klienten senare vill hämta sådan text måste servern koda om den till den kodning som klienten förväntar sig.

Om kodningarna som används av klienten i steg 1 och 3 är samma (vilket vanligtvis är fallet, speciellt när klienten i båda fallen är samma applikation), då går det ofta obemärkt förbi om klienten använder en annan kodning än den den sa att den skulle göra. Anta till exempel att klienten säger till MySQL att den kommer att använda latin1 , men skickar faktiskt data i utf8 :

  • Strängen 'Jazz–Man' skickas till servern i UTF-8 som 0x4a617a7ae280934d616e .

  • MySQL, som avkodar dessa bytes i Windows-1252, förstår att de representerar strängen 'Jazz–Man' .

  • För att lagra i en utf8 kolumn, omkodar MySQL strängen till dess UTF-8-kodning 0x4a617a7ac3a2e282ace2809c4d616e . Detta kan verifieras genom att använda SELECT HEX(name) FROM lessons WHERE id=79510 .

  • När klienten hämtar värdet tror MySQL att den vill ha det i latin1 och så omkodas till Windows-1252-kodningen 0x4a617a7ae280934d616e .

  • När klienten tar emot dessa bytes avkodar den dem som UTF-8 och förstår därför att strängen är 'Jazz–Man' .

Slutsats :klienten inser inte att något är fel. Problem upptäcks bara när en annan klient (en som inte anger sin UTF-8-anslutning felaktigt som latin1 ) försöker använda tabellen. I ditt fall inträffade detta när mysqldump fick en export av data; med --default-character-set=latin1 --skip-set-charset options tvingade effektivt mysqldump att bete sig på samma trasiga sätt som din applikation, så det slutade med korrekt kodad data.

För att åtgärda problemet framöver måste du:

  1. Konfigurera din applikation så att den ställer in sin MySQL-anslutningsteckenuppsättning korrekt (t.ex. set encoding: utf8 i config/database.yml för skenor);

  2. Koda om data i din databas, t.ex. UPDATE lessons SET name = BINARY CONVERT(name USING latin1) (observera att detta måste göras för varje felkodad textkolumn).

Observera också att du förmodligen kommer att vilja utföra dessa två åtgärder atomärt, vilket kan kräva lite eftertanke.



  1. InMemory DUBLIKAT Förvirring i Oracle RAC

  2. TIME_FORMAT() Exempel – MySQL

  3. Vad är STATISTIK TID i SQL Server?

  4. Vad är syftet med den här typen av SQL-injektion?