01Problem
Bu blogun eski sürümünde tablolar latin5 karakter setiyle oluşturulmuştu, ama PHP tarafındaki bağlantı yıllar içinde utf8mb4 olarak güncellenmişti. Sonuç tanıdık: bazı başlıklar düzgün, bazılarında ı gibi bozuk karakterler, emojiler ise hiç kaydedilmiyor.
İlk refleks şu komutu çalıştırmak olur:
ALTER TABLE iq_page
CONVERT TO CHARACTER SET utf8mb4
COLLATE utf8mb4_tr_0900_ai_ci;
Veri gerçekten latin5 ise bu komut doğru çalışır. Ama yıllarca yanlış bağlantı ayarıyla yazılmış bir tabloda verinin bir kısmı zaten UTF-8 baytları olarak duruyor olabilir. O durumda bu komut, bozuk veriyi bir kez daha kodlar ve geri dönüşü zorlaşır.
02Teşhis: bayt bayt bakmak
Ekranda gördüğünüz karaktere değil, diskteki bayta bakın. Türkçe karakter içerdiğini bildiğiniz birkaç satırı HEX() ile inceleyin ve aşağıdaki tabloyla karşılaştırın:
| Karakter | latin5 | UTF-8 | Çift kodlanınca |
|---|---|---|---|
| ı | FD | C4 B1 | ı |
| ğ | F0 | C4 9F | Ä + kontrol karakteri |
| ç | E7 | C3 A7 | ç |
latin5 bir sütunda C4B1 görüyorsanız, o satır latin5 değil; latin5 kılığına girmiş UTF-8'dir.
03İki senaryo, iki yöntem
Veri gerçekten latin5 ise yukarıdaki CONVERT TO komutu yeterlidir. MySQL her baytı doğru UTF-8 karşılığına çevirir.
Veri çift kodlanmışsa MySQL'e "bu baytlara dokunma, sadece etiketini değiştir" demek gerekir. Bunun yolu sütunu önce ikili (binary) türe, sonra hedef karakter setine çevirmektir:
-- 1) Etiketi kaldır: baytlar olduğu gibi kalır
ALTER TABLE iq_page
MODIFY baslik VARBINARY(1020),
MODIFY icerik MEDIUMBLOB;
-- 2) Doğru etiketi ver: baytlar artık UTF-8 olarak okunur
ALTER TABLE iq_page
MODIFY baslik VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL,
MODIFY icerik MEDIUMTEXT CHARACTER SET utf8mb4 NOT NULL;
ALTER yetmez. Satırları önce HEX() ile sınıflandırıp yeni bir tabloya ayrı ayrı taşımak daha güvenlidir.04Collation tuzakları
MySQL 8 için Türkçe sıralama kurallarını en doğru uygulayan collation utf8mb4_tr_0900_ai_ci'dir. ı/I ve i/İ çiftlerini doğru eşler, sıralamayı alfabeye göre yapar.
Ancak URL ve slug gibi benzersiz sütunlarda büyük-küçük harf duyarsız bir collation sürpriz çakışmalara yol açabilir. Bu sütunlar için ascii_bin ya da utf8mb4_bin kullanmak, eşitliğin her zaman bayt bayt kontrol edilmesini sağlar.
05Kontrol listesi
- Tam yedek alın ve geri yüklemeyi bir kez deneyin.
- Her metin sütunu için
HEX()örneklemesi yapın; latin5 ve çift kodlanmış satırları sayın. - Senaryoya göre
CONVERT TOya da binary üzerinden dönüşümü seçin. - Tablo varsayılanını da güncelleyin:
DEFAULT CHARACTER SET utf8mb4. - Bağlantıda
utf8mb4kullanıldığını uygulama tarafında doğrulayın. - Rastgele 50 satırı gözle kontrol edin. Bir emoji ekleyip kaydedin.