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, а значения 👽💔 только что оказались двумя sqaures (я думаю, что это представление нулевого символа)
Вся помощь очень ценится!
Ответы
Ответ 1
То, что у вас есть, - EXTRATERRESTRIAL ALIEN (U+1F47D)
и 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
и collaction должен быть 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 будет использовать эту настройку до тех пор, пока символьная кодировка не будет установлена в строке подключения. Это эквивалентно автоматическому определению набора символов.
Настройте ваши столбцы и базу данных, а также:
var1 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL
Опять же, ваша версия MySQL должна быть относительно современной для поддержки utf8mb4.
Ответ 2
Как ни странно, я обнаружил, что REMOVING &characterEncoding=UTF-8
из JDBC url
мне с подобными проблемами.
Основываясь на моих свойствах,
jdbc_url=jdbc:mysql://localhost:3306/dbName?useUnicode=true
Я думаю, что это поддерживает то, что сказал @Esailija выше, то есть мой MySQL, который на самом деле является 5.5, выясняет свой любимый вкус кодировки UTF-8.
(Обратите внимание, я также указываю InputStream
я читаю, как UTF-8
в коде Java, что, вероятно, не повредит)...
Ответ 3
В общем, для сохранения символов, требующих 4 байта, вам необходимо обновить набор characher и сортировку для utf8mb4
:
- таблица/столбец базы данных:
alter table <some_table> convert to character set utf8mb4 collate utf8mb4_unicode_ci
- соединение с сервером базы данных (см.)
В моей разработке enviromnt для # 2 я предпочитаю устанавливать параметры в командной строке при запуске сервера:
mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
btw, обратите внимание на поведение коннектора /J с помощью SET NAMES 'utf8mb4'
:
Не выдавайте имена наборов запросов с помощью Connector/J, так как драйвер не обнаружит, что набор символов изменился, и будет продолжать использовать набор символов, обнаруженный во время начальной настройки соединения.
И не следует устанавливать параметр characterEncoding
в URL-адресе подключения, поскольку он будет переопределять настроенную кодировку сервера:
Чтобы переопределить автоматически обнаруженную кодировку на стороне клиента, используйте свойство characterEncoding в URL-адресе, используемом для подключения к серверу.
Ответ 4
Как я решил свою проблему.
У меня был
?useUnicode=true&characterEncoding=UTF-8
В моем hibernate подключении jdbc url и я изменили тип данных строки на longtext в базе данных, который раньше был varchar.
Ответ 5
Я столкнулся с той же проблемой и решил ее, установив Collation на utf8_general_ci для каждого столбца.
Ответ 6
Добавьте строку useUnicode=true&characterEncoding=UTF-8
к URL-адресу jdbc.
В вашем случае данные не отправляются с использованием UTF-8
.
Ответ 7
Я думаю, что MySQL не считает это действительным текстом UTF8. Я попробовал вставку в тестовую таблицу с тем же определением столбцов (соединение с mysql-клиентом также было UTF8), и хотя он вставлял, данные, которые я получил с клиентом MySQL CLI, а также JDBC, неправильно отображали значения. Чтобы убедиться, что UTF8 работает правильно, я вставил вместо "o" для obama "ö":
[email protected]:~$ mysql -vvv test < insert.sql
--------------
insert into utf8_test values(_utf8 "walmart öbama 👽💔")
--------------
Query OK, 1 row affected, 1 warning (0.12 sec)
[email protected]:~$ 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();
}
}
}
Вывод:
[email protected]:~/workspaces/java/javatest/bin$ java test.sql.Test
test string=walmart öbama 👽💔
retrieved="walmart öbama "
Кроме того, я пробовал одну и ту же вставку с JDBC-соединением, и это привело к тому же исключению, которое вы получаете.
Я считаю, что это ошибка MySQL. Может быть, там уже есть сообщение об ошибке.
Ответ 8
У меня была одна и та же проблема, и после тщательного изучения всех кодировок и выяснения, что с ними все в порядке, я понял, что свойство bugged, которое у меня было в моем классе, было аннотировано как @Column вместо @JoinColumn (javax.presistence; hibernate), и это все ломало.
Ответ 9
выполнять
show VARIABLES like "%char%";
найти набор символов сервера, если не utf8mb4.
установите его в вашем my.cnf, как
vim /etc/my.cnf
добавить одну строку
character_set_server = utf8mb4
наконец перезапустите MySQL
Ответ 10
Этот параметр useOldUTF8Behavior = true работал нормально для меня. Он не дал неправильных строковых ошибок, но он преобразовал специальные символы, такие как Ã, в несколько символов и сохранил в базе данных.
Чтобы избежать подобных ситуаций, я удалил это свойство из параметра JDBC и вместо этого преобразовал тип данных моего столбца в BLOB. Это сработало идеально.
Ответ 11
Кроме того, тип данных может использовать blob install из varchar или text.