Jak naprawić błędy „Nieprawidłowa wartość ciągu”?

162

Po zauważeniu, że aplikacja miała tendencję do odrzucania losowych wiadomości e-mail z powodu nieprawidłowych błędów wartości ciągu, przeszedłem i przełączyłem wiele kolumn tekstowych na użycie utf8zestawu znaków kolumn i domyślnego zestawienia kolumn ( utf8_general_ci), aby je zaakceptować. To naprawiło większość błędów i sprawiło, że aplikacja przestała otrzymywać błędy sql, gdy trafiała również na e-maile inne niż łacińskie.

Mimo to niektóre e-maile nadal powodują, że program napotyka nieprawidłowe wartości błędów: (Incorrect string value: '\xE4\xC5\xCC\xC9\xD3\xD8...' for column 'contents' at row 1)

Kolumna zawartości to MEDIUMTEXTzbiór danych, który używa utf8zestawu znaków i utf8_general_cisortowania kolumn. W tej kolumnie nie ma flag, które mogę przełączać.

Pamiętając, że nie chcę dotykać ani nawet patrzeć na kod źródłowy aplikacji, chyba że jest to absolutnie konieczne:

  • Co powoduje ten błąd? (tak, wiem, że e-maile są pełne przypadkowych śmieci, ale pomyślałem, że utf8 będzie dość liberalne)
  • Jak mogę to naprawić?
  • Jakie są prawdopodobne skutki takiej poprawki?

Jedną rzeczą, którą rozważałem, było przejście na utf8 varchar ([duża liczba]) z włączoną flagą binarną, ale raczej nie znam MySQL i nie mam pojęcia, czy taka poprawka ma sens.

Brian
źródło
3
Sekcja zwłok: rozwiązanie RichieHindle rozwiązało problem i nie wprowadziło żadnych dodatkowych problemów w czasie działania. Może to trochę hack, ale zadziałało i pozwoliło mi uniknąć brudzenia sobie rąk oprogramowaniem innych firm, którego nie do końca rozumiem. W tym momencie zaktualizowaliśmy do nowszej wersji oprogramowania / schematu, który poprawnie obsługuje wszystkie te problemy z kodowaniem (i jest na tyle nowy, że jest faktycznie obsługiwany), dzięki czemu hack jest niepotrzebny.
Brian

Odpowiedzi:

43

"\xE4\xC5\xCC\xC9\xD3\xD8"nieprawidłowy UTF-8. Przetestowano w Pythonie:

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

Jeśli szukasz sposobu na uniknięcie błędów dekodowania w bazie danych, kodowanie cp1252 (aka „Windows-1252” aka „Windows Western European”) jest najbardziej liberalnym kodowaniem - każda wartość bajtu jest prawidłowym punktem kodu.

Oczywiście nie zrozumie już prawdziwego UTF-8, ani żadnego innego kodowania innego niż cp1252, ale brzmi to tak, jakbyś się tym nie przejmował?

RichieHindle
źródło
4
Co dokładnie masz na myśli, mówiąc: „Oczywiście, że nie będzie już rozumieć prawdziwego UTF-8?”
Brian
5
@Brian: Jeśli powiesz, że dajesz mu cp1252, i faktycznie dasz mu UTF-8, powiedzmy café, to źle zinterpretuje to jako café. Nie ulegnie awarii, ale źle zrozumie postacie o wysokiej jakości.
RichieHindle
3
@Richie: Baza danych może szczęśliwie przywołać dane, jak tylko chce, ale jeśli kod php, który je przechwytuje, upycha je w ciągu, to nie zrobi dużej różnicy ... prawda? Nie widzę dokładnie, na co wpływa brak zrozumienia UTF-8.
Brian
7
@Brian: Nie, masz rację. Czas, w którym miałoby to znaczenie, byłby w bazie danych, na przykład, gdybyś użył klauzuli ORDER BY w swoim SQL - sortowanie byłoby trudne, gdybyś miał znaki spoza ASCII.
RichieHindle
11
Odznacz tę odpowiedź jako rozwiązanie, ukrywanie błędu nie jest rozwiązaniem niczego. Wyjmij lampę przegrzania z samochodu, a zobaczysz.
David Vartanian
133

Nie sugerowałbym odpowiedzi Richiesa, ponieważ spieprzysz dane w bazie danych. Nie naprawiałbyś swojego problemu, ale próbowałbyś go "ukryć" i nie byłbyś w stanie wykonać podstawowych operacji na bazie danych z uszkodzonymi danymi.

Jeśli napotkasz ten błąd, albo wysyłane dane nie są zakodowane w UTF-8, albo twoje połączenie nie jest w UTF-8. Najpierw sprawdź, czy źródło danych (plik, ...) naprawdę to UTF-8.

Następnie sprawdź połączenie z bazą danych, powinieneś to zrobić po połączeniu:

SET NAMES 'utf8';
SET CHARACTER SET utf8;

Następnie sprawdź, czy tabele, w których są przechowywane dane, mają zestaw znaków utf8:

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`
;

Na koniec sprawdź ustawienia bazy danych:

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

Jeśli źródło, transport i miejsce docelowe to UTF-8, problem zniknął;)

nico gawenda
źródło
1
@Kariem: To dziwne, ponieważ to ustawienie jest objęte poleceniem SET NAMES, które jest równoważne wywołaniu 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
Drugim poleceniem powinno być SET CHARACTER SET utf8(nie CHARACTER_SET)
Coder
6
Chociaż ta odpowiedź pomaga zbadać problem, nie zawiera odpowiedzi, co zrobić, aby go naprawić. Widzę „latin1” zamiast „utf-8”.
Vanuan
2
ta odpowiedź świetnie wyjaśnia problem, ale bardzo słabo opisuje rozwiązanie (o co prosił OP). @nicogawenda: Jakie są wszystkie zapytania SQL, które należy uruchomić, aby całkowicie rozwiązać problem? Jak naprawić wszystkie istniejące dane?
Clint Eastwood
1
"Jeśli źródłem, transportem i miejscem przeznaczenia są UTF-8, twój problem zniknął;)" to był dla mnie trik
suarsenegger
80

Typy utf-8 MySQL nie są właściwie utf-8 - używa tylko do trzech bajtów na znak i obsługuje tylko podstawową płaszczyznę wielojęzyczną (tj. Bez emoji, bez płaszczyzny astralnej itp.).

Jeśli chcesz przechowywać wartości z wyższych płaszczyzn Unicode, potrzebujesz kodowania utf8mb4 .

moeffju
źródło
9
Myślę, że to prawdopodobnie najlepsza poprawka. Uaktualnij do 5.5 i zamień utf8 na utf8mb4 w powyższych odpowiedziach. Wstawiałem dane utf8 z Twittera, które zawierały emoji lub inne znaki wymagające 4 bajtów.
rmarscher
Załóżmy, że nie będziemy aktualizować do wersji 5.5. Jak tłumimy błędy?
Użytkownik
Przewinęłam o wiele za daleko, aby znaleźć najbardziej użyteczną odpowiedź
handheldblender,
1
10 lat od pierwszego pytania. Niech będzie wiadomo, że kodowanie utf8 w MySQL nie jest właściwym utf8. Użyj utf8mb4! To samo dotyczy MariaDB. W przeciwnym razie nie możesz mieć łez radości 😂
Liam
51

Tabela i pola mają nieprawidłowe kodowanie; jednak można je przekonwertować na UTF-8.

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;
Jiayu Wang
źródło
1
Myślę, że to jest poprawna odpowiedź dla wszystkich. Mam dwie tabele, każda w formacie utf8 varchar. jeden z nich ma błąd, drugi jest w porządku. Nawet jeśli użytkownik „update select” kopiuje z „dobrej” kolumny utf8 do innej tabeli, pojawia się ten sam błąd. Dzieje się tak, ponieważ te dwie tabele są tworzone w różnych wersjach MySQL.
AiShiguang
Tak! To również była błędna konfiguracja z mojej tabeli bazy danych. Myślę, że ta odpowiedź powinna być poprawna. Mój problem polegał na tym, że wybrano sortowanie utf8_unicode_ci zamiast utf8_general_ci. Dzięki :)
jprivillaso
2
Co ta odpowiedź tutaj robi, powinna znajdować się na górze
Sagun Shrestha,
1
ten pomaga, podpowiada, czego spróbować, zamiast tego, co może być nie tak.
Victor Di
Dziękuję Ci! Po prostu bardzo mi pomogło Zmieniłem zestawienie tabeli i pomyślałem, że to powinno być, ale pola nadal były ascii sortowanie ...
Radu.
25

Dzisiaj rozwiązałem ten problem, zmieniając kolumnę na typ „LONGBLOB”, który przechowuje nieprzetworzone bajty zamiast znaków UTF-8.

Jedyną wadą jest to, że sam musisz zająć się kodowaniem. Jeśli jeden klient Twojej aplikacji używa kodowania UTF-8, a inny używa CP1252, możesz mieć wysyłane wiadomości e-mail z nieprawidłowymi znakami. Aby tego uniknąć, zawsze używaj tego samego kodowania (np. UTF-8) we wszystkich aplikacjach .

Odwiedź tę stronę http://dev.mysql.com/doc/refman/5.0/en/blob.html, aby uzyskać więcej informacji na temat różnic między TEXT / LONGTEXT a BLOB / LONGBLOB. W sieci jest również wiele innych argumentów dotyczących tych dwóch.

frankshaka
źródło
1
To rozwiązanie wydaje się najłatwiejsze. Próbowałem kilku innych kodowań bez powodzenia.
Simeon Abolarinwa,
10

Najpierw sprawdź, czy domyślna_nazwa_zestawu_znaków to utf8.

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

Jeśli wynik nie jest utf8, musisz przekonwertować bazę danych. Najpierw musisz zapisać wysypisko.

Aby zmienić kodowanie zestawu znaków na UTF-8 dla wszystkich tabel w określonej bazie danych, wpisz następujące polecenie w wierszu polecenia. Zastąp DBNAME nazwą bazy danych:

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

Aby zmienić kodowanie zestawu znaków na UTF-8 dla samej bazy danych, wpisz następujące polecenie w wierszu polecenia mysql >. Zastąp DBNAME nazwą bazy danych:

ALTER DATABASE DBNAME CHARACTER SET utf8 COLLATE utf8_general_ci;

Możesz teraz ponowić próbę wpisania znaku utf8 do bazy danych. To rozwiązanie pomaga mi, gdy próbuję przesłać 200000 wierszy pliku csv do mojej bazy danych.

Babacar Gningue
źródło
8

Zwykle dzieje się tak, gdy wstawiasz ciągi do kolumn z niekompatybilnym kodowaniem / sortowaniem.

Otrzymałem ten błąd, gdy miałem TRIGGERs, które z jakiegoś powodu dziedziczą sortowanie serwera. Domyślnie mysql to (przynajmniej na Ubuntu) latin-1 ze szwedzkim sortowaniem. Mimo że miałem bazę danych i wszystkie tabele ustawione na UTF-8, musiałem jeszcze ustawić my.cnf:

/etc/mysql/my.cnf:

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

I to musi zawierać listę wszystkich wyzwalaczy z utf8- *:

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

Niektóre ze zmiennych wymienionych przez to powinny mieć również utf-8- * (bez kodowania latin-1 lub innego):

show variables like 'char%';
Ondra Žižka
źródło
6

Chociaż twoje sortowanie jest ustawione na utf8_general_ci, podejrzewam, że kodowanie znaków w bazie danych, tabeli lub nawet kolumnie może być inne.

ALTER TABLE tabale_name MODIFY COLUMN column_name VARCHAR(255)  
CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
Sameera Prasad Jayasinghe
źródło
5

Mam podobny błąd ( Incorrect string value: '\xD0\xBE\xDO\xB2. ...' for 'content' at row 1). Próbowałem zmienić zestaw znaków kolumny na, utf8mb4a potem błąd zmienił się na 'Data too long for column 'content' at row 1'.
Okazało się, że mysql wyświetla mi zły błąd. Przywróciłem zestaw znaków kolumny na utf8i zmieniłem typ kolumny na MEDIUMTEXT. Po tym błąd zniknął.
Mam nadzieję, że to komuś pomoże.
Nawiasem mówiąc, MariaDB w tym samym przypadku (testowałem tam ten sam INSERT) po prostu wyciął tekst bez błędów.

AVKurov
źródło
MySQL też zmęczyłem tak wiele rzeczy, zdałem sobie sprawę, że mysql nie obsługuje 4-bajtowego dekodowania utf-8 w tej wersji i umierałem próbując zrozumieć, co jest tego przyczyną. Najwyraźniej zmiana typu była odpowiedzią, natychmiastowym rozwiązaniem.
Liza,
4

Ten błąd oznacza, że ​​albo masz ciąg z nieprawidłowym kodowaniem (np. Próbujesz wprowadzić ciąg zakodowany w ISO-8859-1 do kolumny zakodowanej w UTF-8) albo kolumna nie obsługuje danych, które próbujesz wprowadzić.

W praktyce ten drugi problem jest spowodowany implementacją MySQL UTF-8, która obsługuje tylko znaki UNICODE, które wymagają 1-3 bajtów, gdy są reprezentowane w UTF-8. Zobacz „Nieprawidłowa wartość ciągu” podczas próby wstawienia UTF-8 do MySQL przez JDBC? dla szczegółów.

Mikko Rantalainen
źródło
2

Rozwiązaniem dla mnie podczas uruchamiania tej niepoprawnej wartości ciągu: „\ xF8” dla błędu kolumny przy użyciu scriptcase było upewnienie się, że moja baza danych jest skonfigurowana dla utf8 general ci, podobnie jak moje sortowania pól. Następnie, kiedy wykonuję import danych z pliku csv, ładuję plik csv do UE Studio, a następnie zapisuję go w formacie utf8 i Voila! Działa jak urok, 29000 rekordów nie ma błędów. Wcześniej próbowałem zaimportować plik CSV utworzony w programie Excel.

mainebrain
źródło
2

Wypróbowałem wszystkie powyższe rozwiązania (wszystkie przynoszą ważne punkty), ale nic nie działało.

Dopóki nie odkryłem, że moje mapowania pól tabeli MySQL w C # używają nieprawidłowego typu: MySqlDbType.Blob . Zmieniłem go na MySqlDbType.Text i teraz mogę napisać wszystkie symbole UTF8, które chcę!

ps Pole tabeli MySQL jest typu „LongText”. Jednak gdy automatycznie wygenerowałem mapowania pól przy użyciu oprogramowania MyGeneration, automatycznie ustawiłem typ pola na MySqlDbType.Blob w języku C #.

Co ciekawe, od wielu miesięcy używam typu MySqlDbType.Blob ze znakami UTF8 bez żadnych problemów, aż pewnego dnia spróbowałem napisać ciąg znaków zawierający określone znaki.

Mam nadzieję, że pomoże to komuś, kto stara się znaleźć przyczynę błędu.

Ugnius Ramanauskas
źródło
1

Dodałem binarny przed nazwą kolumny i rozwiązałem błąd zestawu znaków.

wstaw do wartości tableA (binarny ciąg znakównazam1);

Richardhe2007
źródło
1

Cześć, mam również ten błąd, gdy używam moich internetowych baz danych z serwera GoDaddy. Myślę, że ma wersję mysql 5.1 lub wyższą. ale kiedy robię to z mojego serwera localhost (wersja 5.7), było dobrze, po tym utworzyłem tabelę z serwera lokalnego i skopiowałem na serwer online za pomocą mysql yog, myślę, że problem dotyczy zestawu znaków

Zrzut ekranu tutaj

Hashain Lakshan
źródło
1

Aby naprawić ten błąd, zaktualizowałem moją bazę danych MySQL do utf8mb4, która obsługuje pełny zestaw znaków Unicode, postępując zgodnie z tym szczegółowym samouczkiem . Proponuję uważnie przejść przez to, ponieważ jest sporo pułapek (np. Klucze indeksu mogą stać się zbyt duże z powodu nowego kodowania, po którym trzeba zmodyfikować typy pól).

metakermit
źródło
1

Tutaj są dobre odpowiedzi. Po prostu dodaję swój, ponieważ napotkałem ten sam błąd, ale okazało się, że jest to zupełnie inny problem. (Może pozornie to samo, ale inna przyczyna.)

U mnie błąd wystąpił dla następującego pola:

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

Kończy się to zapisaniem w bazie danych jako binarnej serializacji URIklasy. Nie spowodowało to żadnych oznak testów jednostkowych (przy użyciu H2) ani testów CI / integracji (przy użyciu MariaDB4j ), ale wybuchło w naszej konfiguracji przypominającej produkcję. (Chociaż po zrozumieniu problemu łatwo było zobaczyć niewłaściwą wartość w instancji MariaDB4j; po prostu nie wysadziło to testu). Rozwiązaniem było zbudowanie niestandardowego mapowania typu:

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));
        }
    }
}

Używane w następujący sposób:

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

Jeśli chodzi o Hibernate, wydaje się, że ma kilka dostarczonych maperów typu , w tym dla java.net.URL, ale nie dla java.net.URI(czego potrzebowaliśmy tutaj).

Sander Verhagen
źródło
1

W moim przypadku ten problem został rozwiązany poprzez zmianę kodowania kolumny MySQL na „binarne” (typ danych zostanie automatycznie zmieniony na VARBINARY). Prawdopodobnie nie będę mógł filtrować ani wyszukiwać w tej kolumnie, ale nie potrzebuję tego.

WilyDen
źródło
1

Jeśli zdarzy ci się przetworzyć wartość za pomocą jakiejś funkcji łańcuchowej przed zapisaniem, upewnij się, że funkcja ta może poprawnie obsługiwać znaki wielobajtowe. Funkcje łańcuchowe, które nie mogą tego zrobić i na przykład próbują obciąć, mogą podzielić jeden z pojedynczych znaków wielobajtowych w środku, co może powodować takie sytuacje z błędami w łańcuchach.

Na przykład w PHP musiałbyś przełączyć się z substrna mb_substr.

WoodrowShigeru
źródło
0

W moim przypadku najpierw spotkałem „???” na mojej stronie internetowej, następnie sprawdzam zestaw znaków MySQL, który jest teraz łaciński, więc zmieniam go na utf-8, a następnie ponownie uruchamiam projekt, potem pojawia się ten sam błąd z tobą, a potem stwierdziłem, że zapomniałem zmienić kodowanie bazy danych i zmień na utf-8, bum, zadziałało.

acoder2013
źródło
0

Próbowałem prawie wszystkich wymienionych tutaj kroków. Żaden nie działał. Pobrany plik mariadb. Zadziałało. Wiem, że to nie jest rozwiązanie, ale może pomóc komuś szybko zidentyfikować problem lub dać tymczasowe rozwiązanie.

Server version: 10.2.10-MariaDB - MariaDB Server
Protocol version: 10
Server charset: UTF-8 Unicode (utf8)
cherankrish
źródło
0

W moim przypadku Incorrect string value: '\xCC\x88'...problem polegał na tym, że o-umlaut był w stanie rozłożonym. To pytanie i odpowiedź pomogły mi zrozumieć różnicę między i ö. W PHP rozwiązaniem dla mnie było użycie biblioteki PHP Normalizer . Np Normalizer::normalize('o¨', Normalizer::FORM_C).

MM.
źródło
-2

1 - Musisz zadeklarować w związku właściwość kodowania UTF8. http://php.net/manual/en/mysqli.set-charset.php .

2 - Jeśli używasz linii poleceń mysql do wykonania skryptu, musisz użyć flagi, takiej jak: 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

Roger Gusmao
źródło