java.sql.SQLException: неверное строковое значение: '\xF0\x9F\x91\xBD\xF0\x9F'

У меня есть следующее строковое значение: "walmart obama ????????"

Я использую MySQL и Java.

Я получаю следующее исключение: `java.sql.SQLException: неверное строковое значение: '\xF0\x9F\x91\xBD\xF0\x9F...'

Вот переменная, которую я пытаюсь вставить:

var1 varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL`

Мой код Java, который пытается вставить «walmart obama ????????», является подготовленным заявлением. Поэтому я использую метод setString().

Похоже, проблема в кодировке значений ????????. Как я могу это исправить? Раньше я использовал Derby SQL, и значения ???????? просто оказались двумя квадратами (я думаю, что это представление нулевого символа)

Вся помощь очень ценится!


person CodeKingPlusPlus    schedule 30.11.2012    source источник
comment
Похоже на дубликат stackoverflow.com/questions/10957238/   -  person Joshua Davis    schedule 11.04.2018
comment
Когда вы создаете базу данных, вы можете указать набор символов и сопоставление следующим образом: CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;   -  person Max Peng    schedule 06.09.2019


Ответы (11)


У вас есть EXTRATERRESTRIAL ALIEN (U+1F47D) и BROKEN HEART (U+1F494), которые не находятся в базовой многоязычной плоскости. Они даже не могут быть представлены в java как один символ, "????????".length() == 4. Это определенно не нулевые символы, и вы увидите квадраты, если вы не используете шрифты, которые их поддерживают.

MySQL utf8 поддерживает только базовую многоязычную плоскость, и вам нужно использовать utf8mb4 вместо:

Для дополнительного символа utf8 вообще не может хранить символ, в то время как utf8mb4 требует для его хранения четыре байта. Поскольку utf8 вообще не может хранить символ, у вас нет дополнительных символов в столбцах utf8, и вам не нужно беспокоиться о преобразовании символов или потере данных при обновлении данных utf8 из более старых версий MySQL.

Таким образом, для поддержки этих символов ваш MySQL должен быть 5.5+, и вам нужно везде использовать utf8mb4. Кодировка соединения должна быть utf8mb4, набор символов должен быть utf8mb4, а сопоставление должно быть utf8mb4. Для java это все еще просто "utf-8", но MySQL нуждается в различии.

Я не знаю, какой драйвер вы используете, но независимый от драйвера способ установить кодировку соединения - отправить запрос:

SET NAMES 'utf8mb4'

Сразу после подключения.

См. также это для Connector/J:

14.14: Как я могу использовать 4-байтовые UTF8, utf8mb4 с Connector/J?

Чтобы использовать 4-байтовый UTF8 с Connector/J, настройте сервер MySQL с character_set_server=utf8mb4. Затем Connector/J будет использовать этот параметр, если в строке подключения не задано значение characterEncoding. Это эквивалентно автоопределению набора символов.

Настройте также столбцы и базу данных:

var1 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL

Опять же, ваша версия MySQL должна быть относительно актуальной для поддержки utf8mb4.

person Esailija    schedule 07.12.2012
comment
@CodeKingPlusPlus вы изменили все в своей базе данных на utf8mb4, похоже, вы все еще используете utf8_general_ci.. - person Esailija; 07.12.2012
comment
Я изменил все в своей базе данных. Я считаю, что ошибка исходит от Java. Я опубликую подробности завтра, у меня сейчас проблемы с подключением к моей базе данных... - person CodeKingPlusPlus; 07.12.2012
comment
Не используйте SET NAMES с Connector/J: dev.mysql.com/doc/connector-j/en/ Do not issue the query set names with Connector/J, as the driver will not detect that the character set has changed, and will continue to use the character set detected during the initial connection setup. - person bcoughlan; 14.01.2015
comment
Если вы хотите просто избавиться от символов из-за пределов BMP вместо того, чтобы разбираться с беспорядком изменения вашей БД, см. здесь: stackoverflow.com/questions/4035562/ - person Indigenuity; 18.04.2016
comment
У меня та же проблема, я выполнил описанные выше шаги, но не решил ее, пока не изменил набор символов-сервер = utf8mb4 в C:\ProgramData\MySQL\MySQL Server 5.7\my.ini - person fattah.safa; 02.10.2016
comment
Я использовал utf8-mb4 для длинного текста, и мне надоело хранить «бета-символ», это решение (SET NAMES «utf8mb4») было для меня полезным, спасибо. - person user3600935; 06.08.2019
comment
Настоятельно рекомендуем добавить это дополнение из последняя версия часто задаваемых вопросов по Connector/J: For 5.1.47 and later: You can use characterEncoding=UTF-8 to use utf8mb4, even if character_set_server on the server has been set to something else. Это помогает, когда вы не можете или не хотите изменять character_set_server в своем экземпляре сервера MySQL. - person Ruslan Stelmachenko; 11.03.2020

Как ни странно, я обнаружил, что УДАЛЕНИЕ &characterEncoding=UTF-8 из JDBC url помогло мне с подобными проблемами.

Судя по моим свойствам,

jdbc_url=jdbc:mysql://localhost:3306/dbName?useUnicode=true

Я думаю, что это поддерживает то, что @Esailija сказал выше, то есть мой MySQL, который действительно 5.5, выясняет свой любимый вариант кодировки UTF-8.

(Обратите внимание, я также указываю InputStream, из которого я читаю, как UTF-8 в коде Java, что, вероятно, не повредит)...

person jsh    schedule 10.09.2013
comment
Может быть, useUnicode=true и не нужно? В моем случае единственное, что сработало, — это глобальная установка character_set_server=utf8mb4 на сервере (группа параметров RDS) и НЕ наличие какого-либо characterEncoding в URL-адресе JDBC. - person Joshua Davis; 11.04.2018

В общем, чтобы сохранить символы, требующие 4 байта, вам нужно обновить набор символов и сопоставление для utf8mb4:

  1. таблица/столбец базы данных: alter table <some_table> convert to character set utf8mb4 collate utf8mb4_unicode_ci
  2. подключение к серверу базы данных (см.)

В моей среде разработки для # 2 я предпочитаю устанавливать параметры в командной строке при запуске сервера: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci


Кстати, обратите внимание на поведение Connector/J с SET NAMES 'utf8mb4':

Не вводите имена наборов запросов с помощью Connector/J, так как драйвер не обнаружит, что набор символов изменился, и будет продолжать использовать набор символов, обнаруженный во время первоначальной установки соединения.

И избегайте установки параметра characterEncoding в URL-адресе подключения, так как он переопределит настроенную кодировку сервера:

Чтобы переопределить автоматически обнаруженную кодировку на стороне клиента, используйте свойство characterEncoding в URL-адресе, используемом для подключения к серверу.

person rilaby    schedule 22.12.2015

Как я решил свою проблему.

я имел

?useUnicode=true&amp;characterEncoding=UTF-8

В моем URL-адресе подключения jdbc в спящем режиме я изменил строковый тип данных на длинный текст в базе данных, который раньше был varchar.

person Community    schedule 24.10.2013
comment
Отлично, если вам не нужен индекс этого столбца и он относительно мал, но я могу проделать этот трюк для всех своих столбцов. - person shareef; 08.09.2018

Я столкнулся с той же проблемой и решил ее, установив для параметра Сопоставление значение utf8_general_ci для каждого столбца.

person Appy    schedule 26.05.2015

Добавьте строку useUnicode=true&amp;characterEncoding=UTF-8 к URL-адресу jdbc.

В вашем случае данные не отправляются с использованием кодировки UTF-8.

person JHS    schedule 30.11.2012
comment
Как добавить это? В моей строке подключения? Я использую Netbeans, если это помогает. - person CodeKingPlusPlus; 01.12.2012
comment
Как вы создаете связь? - person JHS; 01.12.2012
comment
DriverManager.getConnection(jdbc:mysql://localhost:####/[dbName], [имя пользователя], [пароль]); - person CodeKingPlusPlus; 01.12.2012
comment
Сделайте это так: DriverManager.getConnection(jdbc:mysql://localhost:####/[dbName]?useUnicode=truecharacterEncoding=UTF-8, [имя пользователя], [пароль]); - person JHS; 01.12.2012
comment
Сотрите это, я забыл '?' Но теперь я вернулся к той же ошибке, что и в исходном сообщении... - person CodeKingPlusPlus; 01.12.2012

Я предполагаю, что MySQL не считает, что это допустимый текст UTF8. Я попытался вставить в тестовую таблицу с тем же определением столбца (подключение клиента mysql также было UTF8), и хотя вставка была выполнена, данные, которые я получил с помощью клиента MySQL CLI, а также JDBC, не извлекли значения правильно. Чтобы убедиться, что UTF8 работает правильно, я вставил «ö» вместо «o» для obama:

johan@maiden:~$ mysql -vvv test < insert.sql 
--------------
insert into utf8_test values(_utf8 "walmart öbama ????????")
--------------

Query OK, 1 row affected, 1 warning (0.12 sec)

johan@maiden:~$ file insert.sql 
insert.sql: UTF-8 Unicode text

Небольшое Java-приложение для тестирования:

package test.sql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class Test
{

    public static void main(String[] args)
    {
        System.out.println("test string=" + "walmart öbama ????????");
        String url = "jdbc:mysql://hostname/test?useUnicode=true&characterEncoding=UTF-8";
        try
        {
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            Connection c = DriverManager.getConnection(url, "username", "password");
            PreparedStatement p = c.prepareStatement("select * from utf8_test");
            p.execute();
            ResultSet rs = p.getResultSet();
            while (!rs.isLast())
            {
                rs.next();
                String retrieved = rs.getString(1);
                System.out.println("retrieved=\"" + retrieved + "\"");

            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

}

Вывод:

johan@appel:~/workspaces/java/javatest/bin$ java test.sql.Test
test string=walmart öbama ????????
retrieved="walmart öbama "

Кроме того, я пробовал ту же вставку с соединением JDBC, и она вызвала то же исключение, что и вы. Я считаю, что это ошибка MySQL. Может уже есть баг-репорт о такой ситуации..

person Friek    schedule 06.12.2012
comment
Кстати, символы в вашей строке даже не отображаются правильно как в Firefox, так и в Chrome на OSX. Они правильно отображаются в моем приложении iTerm. Я думаю, это зависит от шрифта. - person Friek; 06.12.2012

У меня была такая же проблема, и после тщательного изучения всех кодировок и обнаружения того, что с ними все в порядке, я понял, что свойство с ошибками, которое у меня было в моем классе, было аннотировано как @Column вместо @JoinColumn (javax.presistence; hibernate) и это все ломало.

person jon    schedule 18.02.2015

Этот параметр useOldUTF8Behavior=true у меня отлично работал. Он не выдавал неправильных строковых ошибок, но преобразовывал специальные символы, такие как Ã, в несколько символов и сохранял их в базе данных.

Чтобы избежать таких ситуаций, я удалил это свойство из параметра JDBC и вместо этого преобразовал тип данных моего столбца в BLOB. Это сработало идеально.

person Prithu Kumar    schedule 28.01.2019
comment
Не могли бы вы добавить больше подробностей в свой ответ? (код, команды и т.д.) - person aBnormaLz; 28.01.2019

выполнять

show VARIABLES like "%char%”;

найти сервер набора символов, если это не utf8mb4.

установите его в свой my.cnf, например

vim /etc/my.cnf

добавить одну строку

character_set_server = utf8mb4

наконец перезапустите mysql

person Kevin Hawk    schedule 05.07.2018
comment
character_set_server это вариант, НЕ character-set-server - person Arun S R; 03.06.2019

Кроме того, тип данных может использовать установку blob для varchar или text.

person barry xu    schedule 23.09.2018
comment
Вы не хотите этого - person ECostello; 11.12.2019