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

Вся допомога дуже вдячна!



Створюючи базу даних, ви можете надати набір символів і порівняння таким чином: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-сервер з символом_set_server = utf8mb4. Тоді Connector / J буде використовувати це налаштування до тих пір, поки в рядку з'єднання не буде встановлено символEncoding . Це еквівалентно автоматичному виявленню набору символів.

Відрегулюйте також свої стовпці та базу даних:

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
У мене така ж проблема, виконуючи вказані вище кроки, але не вирішили, поки не змінили набір символів-сервера = 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


btw, зверніть увагу на поведінку 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), а НЕ має жодного символуEncoding у URL-адресі JDBC.
Джошуа Девіс

6

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

я мав

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

У моєму сплячому URL-адресі підключення jdbc я змінив тип даних рядка на довгий текст у базі даних, який раніше був varchar.


Створіть, якщо вам не потрібен цей стовпчик, індексований і його відносно невеликий, але я можу зробити цей трюк для всіх моїх стовпців, хоча
shareef

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 на OSX. Вони правильно відображаються в моєму додатку iTerm. Я думаю, це залежить від шрифту.
Фрік

1

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


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

Щоб уникнути подібних ситуацій, я видалив цю властивість із параметра JDBC і замість цього перетворив тип даних мого стовпця в BLOB. Це спрацювало ідеально.


Чи можете ви, будь ласка, додати більше відповіді до своєї відповіді? (код, команди тощо)
aBnormaLz

-2

Крім того, тип даних може використовувати інсталяцію варшара або текст.


Ви цього не хочете
ECostello
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.