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


107

У меня есть следующее строковое значение: "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, и значения 👽💔 просто оказались двумя sqaures (я думаю, что это представление нулевого символа)

Любая помощь приветствуется!



Когда вы создаете базу данных, вы можете указать набор символов и сопоставление следующим образом:CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Макс Пэн,

Ответы:


145

То, что у вас есть, 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.


Посмотрите мой другой пост по теме: stackoverflow.com/questions/13748170/… . Если вы можете на него ответить, значит, вы ответили и на этот вопрос. В другом посте есть более подробная информация о том, что я сделал.
CodeKingPlusPlus

1
@CodeKingPlusPlus, вы изменили все в своей базе данных на utf8mb4, похоже, вы все еще используете utf8_general_ci..
Esailija

1
Не выполняйте «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.
bcoughlan

1
Если вы хотите просто избавиться от символов вне BMP вместо того, чтобы разбираться с беспорядком, связанным с изменением вашей БД, см. Здесь: stackoverflow.com/questions/4035562/…
Indigenuity

2
У меня такая же проблема, я выполнил описанные выше шаги, но не решил ее до тех пор, пока не изменил параметр character-set-server = utf8mb4 в C: \ ProgramData \ MySQL \ MySQL Server 5.7 \ my.ini
fattah.safa

16

В общем, чтобы сохранить символы, требующие 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-адресе, используемом для подключения к серверу.


15

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

Исходя из моих свойств,

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

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

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


Может useUnicode=trueдаже не нужно? В моем случае единственное, что сработало, - это character_set_server=utf8mb4глобальная настройка на сервере (группа параметров RDS) и НЕ иметь никакого characterEncoding в URL-адресе JDBC.
Джошуа Дэвис

6

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

я имел

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

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


Отлично, если вам не нужен индексированный столбец и он относительно небольшой, но я могу проделать этот трюк для всех своих столбцов
shareef 08

3

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

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


Как мне это добавить? В моей строке подключения? Я использую Netbeans, если это помогает.
CodeKingPlusPlus

Как вы устанавливаете связь?
JHS

DriverManager.getConnection ("jdbc: mysql: // localhost: #### / [dbName]", [имя пользователя], [пароль]);
CodeKingPlusPlus

Сделайте это так - DriverManager.getConnection ("jdbc: mysql: // localhost: #### / [dbName]? UseUnicode = true & amp; characterEncoding = UTF-8", [имя пользователя], [пароль]);
JHS

1
Сотрите это, я забыл '?' Но теперь я вернулся к той же ошибке, что и исходный пост ...
CodeKingPlusPlus

3

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


2

Я думаю, 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. Может, уже есть сообщение об ошибке в такой ситуации ..


Кстати, символы в вашей строке даже не отображаются правильно ни в Firefox, ни в Chrome на OS X. Они правильно отображаются в моем приложении iTerm. Я думаю, это зависит от шрифта.
Птник, 06

1

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


1

выполнять

show VARIABLES like "%char%”;

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

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

vim /etc/my.cnf

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

character_set_server = utf8mb4

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


1
character_set_serverэто вариант, НЕcharacter-set-server
Arun SR

0

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

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


Не могли бы вы добавить больше подробностей к своему ответу? (код, командиры и т. д.)
aBnormaLz

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.