“Yanlış dize değeri” hataları nasıl düzeltilir?


162

Bir uygulamanın yanlış dize değeri hataları nedeniyle rastgele e-postaları atma eğiliminde olduğunu fark ettikten sonra, yine de gittim ve birçok metin sütununu, utf8sütun karakter kümesini ve varsayılan sütun collate ( utf8_general_ci) kullanmak için onları değiştirecek şekilde değiştirdim. Bu, hataların çoğunu düzeltti ve latin olmayan e-postalara çarptığında uygulamanın sql hataları almayı durdurmasını sağladı.

Buna rağmen, bazı e-postalar programın hatalı dize değeri hatalarına çarpmasına neden oluyor: (Incorrect string value: '\xE4\xC5\xCC\xC9\xD3\xD8...' for column 'contents' at row 1)

İçerik sütunu, sütun karakter kümesini ve sütun harmanlamasını MEDIUMTEXTkullanan bir veri türüdür . Bu sütunda değiştirebileceğim bayrak yok.utf8utf8_general_ci

Kesinlikle gerekli olmadıkça dokunmak veya hatta uygulama kaynak koduna bakmak istemiyorum:

  • Bu hataya ne sebep oluyor? (evet, e-postaların rastgele çöplerle dolu olduğunu biliyorum, ancak utf8'in oldukça hoş olacağını düşündüm)
  • Nasıl düzeltebilirim?
  • Böyle bir düzeltmenin olası etkileri nelerdir?

Düşündüğüm bir şey, ikili bayrak açıkken bir utf8 varchar'a ([bazı büyük sayı]) geçiş yapmaktı, ancak MySQL'e aşina değilim ve böyle bir düzeltmenin mantıklı olup olmadığı hakkında hiçbir fikrim yok.


3
Ölüm sonrası: RichieHindle'ın çözümü sorunu çözdü ve çalışırken herhangi bir ek sorun yaratmadı. Biraz hack olmuş olabilir, ama işe yaradı ve tam olarak anlamadığım 3. taraf yazılımlarla ellerimi kirletmeme izin verdi. Bu noktada, tüm bu kodlama sorunlarını düzgün bir şekilde işleyen (ve aslında desteklenecek kadar yeni olan) yazılımın / şemanın daha yeni bir sürümüne güncelledik, bu da hack'i gereksiz kılıyor.
Brian

Yanıtlar:


43

"\xE4\xC5\xCC\xC9\xD3\xD8"geçerli UTF-8 değil. Python kullanılarak test edilmiştir:

>>> "\xE4\xC5\xCC\xC9\xD3\xD8".decode("utf-8")
...
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 0-2: invalid data

Veritabanındaki kod çözme hatalarından kaçınmanın bir yolunu arıyorsanız, cp1252 kodlaması (diğer adıyla "Windows-1252" aka "Windows Batı Avrupa") en izin verilen kodlamadır - her bayt değeri geçerli bir kod noktasıdır.

Tabii ki artık gerçek UTF-8'i veya diğer cp1252 olmayan kodlamaları anlamayacak, ancak bu konuda fazla endişe duymadığınız anlaşılıyor mu?


4
Tam olarak ne demek istiyorsun, "Tabii ki artık gerçek UTF-8'i anlamayacak mı?"
Brian

5
@Brian: Eğer cp1252 verdiğinizi söylerseniz ve aslında UTF-8'i verirseniz, örneğin café, bunu yanlış yorumlayacaktır café. Çökmeyecek, ancak yüksek bit karakterleri yanlış anlayacaktır.
RichieHindle

3
@Richie: Veritabanı ne olursa olsun verileri mutlu bir şekilde çağırabilir, ancak yakalayan php kodu bir dizeye dolduruyorsa, bu çok fazla fark yaratmayacak mı? UTF-8'in anlaşılmamasının tam olarak nerede bir etkisi olduğunu görmüyorum.
Brian

7
@Brian: Hayır, haklısın. Fark yaratacağı zaman, örneğin SQL'inizde ORDER BY deyimini kullandıysanız, sıralama ASCII olmayan karakterlerin olduğu yerde sakıncalı olur.
RichieHindle

11
Lütfen bu cevabı çözüm olarak işaretleyin, bir hatayı gizlemek hiçbir şeyin çözümü değildir. Aşırı ısınma lambasını arabanızdan çıkarın ve göreceksiniz.
David Vartanian

133

Veritabanının içindeki verileri berbat ettiğiniz için Richies'in yanıtını önermem. Sorununuzu düzeltmezsiniz, ancak "gizlemeye" çalışırsınız ve kesilen verilerle temel veritabanı işlemlerini gerçekleştiremezsiniz.

Bu hatayla karşılaşırsanız, gönderdiğiniz veriler UTF-8 kodlu değildir veya bağlantınız UTF-8 değildir. İlk olarak, veri kaynağının (bir dosya ...) gerçekten UTF-8 olduğunu doğrulayın .

Ardından, veritabanı bağlantınızı kontrol edin, bağladıktan sonra bunu yapmanız gerekir:

SET NAMES 'utf8';
SET CHARACTER SET utf8;

Ardından, verilerin depolandığı tabloların utf8 karakter kümesine sahip olduğunu doğrulayın:

SELECT
  `tables`.`TABLE_NAME`,
  `collations`.`character_set_name`
FROM
  `information_schema`.`TABLES` AS `tables`,
  `information_schema`.`COLLATION_CHARACTER_SET_APPLICABILITY` AS `collations`
WHERE
  `tables`.`table_schema` = DATABASE()
  AND `collations`.`collation_name` = `tables`.`table_collation`
;

Son olarak, veritabanı ayarlarınızı kontrol edin:

mysql> show variables like '%colla%';
mysql> show variables like '%charac%';

Kaynak, ulaşım ve hedef UTF-8 ise, sorununuz ortadan kalkar;)


1
@Kariem: Bu garip, çünkü bu ayar SET character_set_client, SET character_set_results, SET character_set_connection dev.mysql.com/doc/refman/5.1/en/charset-connection.html
nico gawenda

2
İkinci komut SET CHARACTER SET utf8(CHARACTER_SET değil) olmalıdır
Kodlayıcı

6
Bu yanıtlar sorunu araştırmaya yardımcı olmakla birlikte, sorunu çözmek için ne yapılacağına cevap vermez. "Utf-8" yerine "latin1" i görüyorum.
Vanuan

2
bu cevap sorunu açıklamak için harika ama çözümü detaylandırmada çok zayıf (OP'nin istediği budur). @nicogawenda: Sorunu tamamen çözmek için çalıştırılacak tüm SQL sorguları nelerdir? Önceden var olan tüm veriler nasıl düzeltilir?
Clint Eastwood

1
"Kaynak, ulaşım ve hedef UTF-8 ise, sorununuz gitti;)" benim için hüner oldu
suarsenegger

80

MySQL'in utf-8 tipleri aslında uygun utf-8 değildir - karakter başına sadece üç bayt kullanır ve sadece Temel Çok Dilli Düzlem'i destekler (yani Emoji yok, astral düzlem yok, vb.).

Daha yüksek Unicode düzlemlerinden değerleri saklamanız gerekiyorsa utf8mb4 kodlamalarına ihtiyacınız vardır .


9
Bence bu muhtemelen en iyi çözüm. 5.5'e yükseltin ve yukarıdaki cevaplarda utf8 yerine utf8mb4 yazın. Twitter'dan emojileri veya 4 bayt gerektiren diğer karakterleri içeren utf8 verileri ekliyordum.
rmarscher

Diyelim ki 5.5 sürümüne geçmeyeceğiz. Hataları nasıl önleyebiliriz?
Kullanıcı

Ben bu en yararlı cevap için çok uzak kaydırma
handheldblender

1
Orijinal sorudan 10 yıl sonra. MySQL'in utf8 kodlamasının doğru utf8 olmadığı bilinmelidir. Utf8mb4 kullanın! Aynı şey MariaDB için de geçerli. Aksi takdirde sevinç gözyaşlarınız olamaz 😂
Liam

51

Tablo ve alanlar yanlış kodlamaya sahip; ancak bunları UTF-8'e dönüştürebilirsiniz.

ALTER TABLE logtest CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

ALTER TABLE logtest DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

ALTER TABLE logtest CHANGE title title VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci;

1
Bence bu herkesin doğru cevabı. Her biri utf8 varchar biçiminde iki tablo var. biri hata aldı, diğeri iyi. 'kullanıcı' güncelleme seç 'bile' iyi 'utf8 sütunundan başka bir tabloya kopyala, aynı hata oluşur. Çünkü iki tablo MySQL'in farklı sürümlerinde oluşturulmuştur.
AiShiguang

Evet! Veritabanı tablomdan da yanlış yapılandırılmıştı. Bence bu cevap doğru olmalı. Benim sorunum seçilen harmanlama utf8_general_ci yerine utf8_unicode_ci oldu. Teşekkürler :)
jprivillaso

2
Bu cevap burada ne yapıyor, en üstte olmalı
Sagun Shrestha

1
bu yardımcı olur, neyin yanlış olabileceğini değil, ne denemenizi söyler.
Victor Di

Teşekkür ederim! Sadece bana çok yardımcı oldu tablo harmanlama karınca değiştirmiş olmalıydım, öyle olması gerektiğini düşündüm ama alanlar hala ascii harmanlama idi ...
Radu

25

Bu sorunu bugün, sütunu UTF-8 karakterleri yerine ham bayt depolayan 'LONGBLOB' türüne değiştirerek çözdüm.

Bunu yapmanın tek dezavantajı, kodlamaya kendiniz dikkat etmeniz gerektiğidir. Uygulamanızın bir istemcisi UTF-8 kodlaması kullanıyor ve diğeri CP1252 kullanıyorsa, e-postalarınızın yanlış karakterlerle gönderilmesini sağlayabilirsiniz. Bundan kaçınmak için, tüm uygulamalarınızda her zaman aynı kodlamayı (örn. UTF-8) kullanın .

TEXT / LONGTEXT ve BLOB / LONGBLOB arasındaki farklar hakkında daha fazla bilgi için bu sayfaya http://dev.mysql.com/doc/refman/5.0/en/blob.html bakın . İnternette bu ikisini tartışan başka birçok argüman daha var.


1
Bu çözüm en kolay yol gibi görünüyor. Başarısız başka birkaç kodlama denedim.
Simeon Abolarinwa

10

İlk olarak default_character_set_name adınızın utf8 olup olmadığını kontrol edin.

SELECT default_character_set_name FROM information_schema.SCHEMATA S WHERE schema_name = "DBNAME";

Sonuç utf8 değilse veritabanınızı dönüştürmeniz gerekir. İlk önce bir çöplüğü kaydetmelisiniz.

Belirtilen veritabanındaki tüm tablolar için karakter kümesi kodlamasını UTF-8 olarak değiştirmek için, komut satırına aşağıdaki komutu yazın. DBNAME yerine veritabanı adını yazın:

mysql --database=DBNAME -B -N -e "SHOW TABLES" | awk '{print "SET foreign_key_checks = 0; ALTER TABLE", $1, "CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; SET foreign_key_checks = 1; "}' | mysql --database=DBNAME

Veritabanı için karakter kümesi kodlamasını UTF-8 olarak değiştirmek için, mysql > komut istemine aşağıdaki komutu yazın. DBNAME yerine veritabanı adını yazın:

ALTER DATABASE DBNAME CHARACTER SET utf8 COLLATE utf8_general_ci;

Artık veritabanınıza utf8 karakteri yazmayı tekrar deneyebilirsiniz. Bu çözüm veritabanına 200000 satır csv dosyası yüklemeye çalıştığınızda bana yardımcı olur.


8

Genel olarak, bu, uyumsuz kodlama / harmanlama içeren sütunlara dizeler eklediğinizde olur.

Bir sebepten dolayı sunucunun harmanlamasını devralan TRIGGER'larım olduğunda bu hatayı aldım. Ve mysql'in varsayılanı (en azından Ubuntu'da) İsveççe harmanlama ile latin-1'dir. Ben veritabanı ve tüm tablolar UTF-8 olarak ayarlanmış olmasına rağmen, ben henüz ayarlamak zorunda kaldı my.cnf:

/etc/mysql/my.cnf:

[mysqld]
character-set-server=utf8
default-character-set=utf8

Ve bu tüm tetikleyicileri utf8- * ile listelemelidir:

select TRIGGER_SCHEMA, TRIGGER_NAME, CHARACTER_SET_CLIENT, COLLATION_CONNECTION, DATABASE_COLLATION from information_schema.TRIGGERS

Ve bu şekilde listelenen bazı değişkenler de utf-8- * (latin-1 veya başka kodlama yok) içermelidir:

show variables like 'char%';

6

Harmanlamanız utf8_general_ci olarak ayarlanmış olsa da, veritabanı, tablo veya hatta sütunun karakter kodlamasının farklı olabileceğinden şüpheleniyorum.

ALTER TABLE tabale_name MODIFY COLUMN column_name VARCHAR(255)  
CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;

5

Benzer bir hata aldım ( Incorrect string value: '\xD0\xBE\xDO\xB2. ...' for 'content' at row 1). Ben utf8mb4ve sonra hata değişti sütun karakter kümesi değiştirmeye çalıştım 'Data too long for column 'content' at row 1'.
MySQL bana yanlış bir hata gösterdi ortaya çıktı. Sütunun karakter kümesini geri döndürdüm ve sütunun utf8türünü değiştirdim MEDIUMTEXT. Bundan sonra hata kayboldu.
Umarım birine yardımcı olur.
Bu arada MariaDB aynı durumda (orada aynı INSERT'i test ettim) sadece bir metni hatasız kesti.


MySQL de ben çok şey yorgun, fark mysql bu sürümde 4 bayt utf-8 kodlama desteklemiyor ve buna neyin neden olduğunu anlamaya çalışırken ölüyordu. Görünüşe göre türün değiştirilmesi cevap, acil bir çözümdü.
Liza

4

Bu hata ya yanlış kodlamaya sahip dizeye sahip olduğunuz anlamına gelir (örneğin, ISO-8859-1 kodlanmış dizeyi UTF-8 kodlu sütuna girmeye çalışıyorsunuz) ya da sütun girmeye çalıştığınız verileri desteklemiyor demektir.

Uygulamada, ikinci soruna, UTF-8'de temsil edildiğinde 1-3 bayta ihtiyaç duyan UNICODE karakterlerini destekleyen MySQL UTF-8 uygulaması neden olmaktadır. UTF-8'i JDBC aracılığıyla MySQL'e eklemeye çalışırken "Yanlış dize değeri" ne bakın ? detaylar için.


2

Bu Yanlış dize değeri ile çalışırken benim için çözüm: scriptcase kullanarak sütun hatası için '\ xF8' benim veritabanı utf8 genel ci için ayarlandığından emin olmak ve böylece benim alan harmanlama oldu. Sonra bir csv dosyası benim veri alma yaptığımda csv UE Studio yük sonra utf8 ve Voila olarak biçimlendirilmiş kaydedin! Bir cazibe gibi çalışır, 29000 kayıt var hiçbir hata. Daha önce bir excel oluşturulan csv almaya çalışıyordum.


2

Yukarıdaki çözümlerin hepsini denedim (hepsi geçerli puanlar getiriyor), ama benim için hiçbir şey işe yaramadı.

C # benim MySQL tablo alan eşlemeleri yanlış bir tür kullandığını bulana kadar : MySqlDbType.Blob . MySqlDbType.Text olarak değiştirdim ve şimdi istediğim tüm UTF8 sembollerini yazabiliyorum!

ps MySQL tablo alanım "LongText" türündedir. Ancak, MyGeneration yazılımını kullanarak alan eşlemelerini otomatik olarak oluşturduğumda, alan türünü otomatik olarak C # 'da MySqlDbType.Blob olarak ayarlar.

İlginçtir, MySqlDbType.Blob türünü UTF8 karakterleri ile sorunsuz bir şekilde aylarca kullanıyorum, bir güne kadar bazı belirli karakterlerle bir dize yazmayı denedim.

Umarım bu hata için bir neden bulmakta zorlanan birine yardımcı olur.


1

Sütun adından önce ikili kod ekledim ve karakter seti hatasını çözdüm.

tableA değerlerine girin (ikili dize adı);


1

Merhaba ben godaddy sunucusundan çevrimiçi veritabanlarımı kullandığımda bu hatayı aldım ve 5.1 veya daha fazlasının mysql sürümüne sahip olduğunu düşünüyorum. ama localhost sunucumdan (sürüm 5.7) yaptığımda bundan sonra yerel sunucudan tablo oluşturduğumda ve mysql yog kullanarak çevrimiçi sunucuya kopyalandığımda sorun olduğunu düşünüyorum.

Burada Ekran Görüntüsü


1

Bu hatayı düzeltmek için MySQL veritabanımı bu detaylı eğitimi izleyerek tam Unicode karakter setini destekleyen utf8mb4'e yükselttim . Dikkatli bir şekilde geçmenizi öneririm, çünkü oldukça az gotchas var (örn. Alan türlerini değiştirmek zorunda olduğunuz yeni kodlamalar nedeniyle dizin anahtarları çok büyük olabilir).


1

Burada iyi cevaplar var. Aynı hatayla karşılaştığım için benimkini ekliyorum ama tamamen farklı bir sorun olduğu ortaya çıktı. (Belki yüzeyde aynıdır, ancak farklı bir temel sebeptir.)

Benim için aşağıdaki alanda hata oldu:

@Column(nullable = false, columnDefinition = "VARCHAR(255)")
private URI consulUri;

Bu, veritabanında URIsınıfın ikili serileştirmesi olarak depolanır . Bu, birim testi (H2 kullanarak) veya CI / entegrasyon testi ( MariaDB4j kullanarak) ile herhangi bir bayrak yükseltmedi , üretim benzeri kurulumumuzda patladı. (Sorun bir kez anlaşıldıktan sonra, MariaDB4j örneğinde yanlış değeri görmek yeterince kolaydı; sadece testi havaya uçurmadı.) Çözüm, özel bir tür eşleyici oluşturmaktı:

package redacted;

import javax.persistence.AttributeConverter;
import java.net.URI;
import java.net.URISyntaxException;

import static java.lang.String.format;

public class UriConverter implements AttributeConverter<URI, String> {
    @Override
    public String convertToDatabaseColumn(URI attribute) {
        return attribute.toString();
    }

    @Override
    public URI convertToEntityAttribute(String field) {
        try {
            return new URI(field);
        }
        catch (URISyntaxException e) {
            throw new RuntimeException(format("could not convert database field to URI: %s", field));
        }
    }
}

Aşağıdaki gibi kullanılır:

@Column(nullable = false, columnDefinition = "VARCHAR(255)")
@Convert(converter = UriConverter.class)
private URI consulUri;

Hazırda Bekletme söz konusu olduğunda, bunun için dahil , ancak değil (burada ihtiyaç duyduğumuz şey) dahil olmak üzere bir dizi sağlanan tip haritacıya sahip olduğu görülüyor .java.net.URLjava.net.URI


1

Benim durumumda bu sorun Mysql sütun kodlaması 'binary' olarak değiştirilerek çözüldü (veri tipi otomatik olarak VARBINARY olarak değiştirilecek). Muhtemelen bu sütunu filtreleyemeyeceğim veya arayamayacağım, ancak buna ihtiyacım yok.


1

Kaydetmeden önce değeri bazı dize işlevleriyle işlerseniz, işlevin çok baytlı karakterleri düzgün bir şekilde işleyebildiğinden emin olun. Bunu yapamayan ve örneğin kesmeye çalışan dize işlevleri, ortadaki tek çok baytlı karakterlerden birini bölebilir ve bu da dize hata durumlarına neden olabilir.

Örneğin PHP, sen geçmek gerekir substriçin mb_substr.


0

Benim durumumda, önce bir '???' web sitemde, sonra şimdi latin olan Mysql karakter setini kontrol ediyorum, bu yüzden utf-8 olarak değiştirdim, sonra projemi yeniden başlatıyorum, sonra sizinle aynı hatayı aldım, sonra veritabanının charsetini değiştirmeyi unuttuğumu buldum ve utf-8 olarak değişti, patladı, işe yaradı.


0

Burada bahsedilen hemen hemen her adımı denedim. Hiçbiri işe yaramadı. İndirildi mariadb. İşe yaradı. Bunun bir çözüm olmadığını biliyorum, ama bu birisinin sorunu hızlı bir şekilde tanımlamasına veya geçici bir çözüm vermesine yardımcı olabilir.

Server version: 10.2.10-MariaDB - MariaDB Server
Protocol version: 10
Server charset: UTF-8 Unicode (utf8)


-2

1 - Bağlantınızda, UTF8'i geliştirmenin uygunluğunu beyan etmelisiniz. http://php.net/manual/en/mysqli.set-charset.php .

2 - Bir komut dosyasını yürütmek için mysql komando satırını kullanıyorsanız, bayrağı aşağıdaki gibi kullanmanız gerekir: Cmd: C:\wamp64\bin\mysql\mysql5.7.14\bin\mysql.exe -h localhost -u root -P 3306 --default-character-set=utf8 omega_empresa_parametros_336 < C:\wamp64\www\PontoEletronico\PE10002Corporacao\BancoDeDadosModelo\omega_empresa_parametros.sql

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.