Данные UTF-8 в базе данных Latin1: можно ли их сохранить?

У меня есть приложение rails, которое получает данные с устройства Android. Я заметил, что некоторые данные на японском не сохранены правильно. Он отображается в виде буквенных вопросительных знаков (не алмазных) в клиенте MySQL и на веб-сайте rails.

Оказывается, база данных, которую я подключил к приложению rails, настроена на Latin1. Rails установлен в UTF-8.

Я много читал о кодировках символов, но все они упоминают, что данные как-то немного читаются. Мой, однако, только буквальные знаки вопроса. Попытка конвертировать данные в UTF-8 с использованием нескольких методов в Интернете ничего не меняет. Я подозреваю, что данные преобразуются в вопросительные знаки при записи в базу данных.

Пример вывода из консоли MySQL:

select * from foo where bar = "foobar";
+-------+------+------------------------+---------------------+---------------------+
| id    | name | bar                    | created_at          | updated_at          |
+-------+------+------------------------+---------------------+---------------------+
| 24300 | ???? | foobar                 | 2012-01-23 05:04:22 | 2012-01-23 05:04:22 |
+-------+------+------------------------+---------------------+---------------------+
1 row in set (0.00 sec)

Исходные данные, полученные моим приложением rails от клиента Android:

name = 爆笑笑話

Эти входные данные были проверены на наличие в приложении rails перед сохранением в базе данных. Так что это не искажено в клиенте Android или во время передачи на сервер. Есть ли шанс, что я смогу вернуть эти данные? Или это полностью потеряно?

1 ответ

Решение

На самом деле очень легко думать, что данные кодируются одним способом, тогда как на самом деле они кодируются другим способом: это потому, что любая попытка прямого получения данных приведет к преобразованию сначала в набор символов вашего соединения с базой данных, а затем в набор символов вашего выходного носителя - поэтому вы должны сначала проверить фактическое кодирование ваших сохраненных данных через SELECT BINARY name FROM foo WHERE bar = 'foobar' или же SELECT HEX(name) FROM foo WHERE bar = 'foobar',

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

  • 0xe78886, указывая, что ваш столбец на самом деле содержит данные в кодировке UTF-8: это обычно происходит, когда для набора символов соединения с базой данных, над которым был первоначально вставлен текст, было установлено значение latin1 но на самом деле данные в кодировке UTF-8 были отправлены.

    Вы должны видеть ? символы при извлечении данных, потому что что-то между хранилищем данных и дисплеем не может перекодировать эти байты (однако, учитывая, что MySQL считает, что они представляют 爆 и эти символы, вероятно, доступны в большинстве наборов символов, маловероятно, что они встречаются в самом MySQL (если вы явно не корректируете информацию о кодировке во время поиска).

    В любом случае, если это так, вам нужно удалить информацию о кодировке из столбца, а затем сообщить MySQL, что данные на самом деле кодируются как UTF-8. Как указано в ALTER TABLE Синтаксис:

    Предупреждение

    CONVERT TO Операция преобразует значения столбцов между наборами символов. Это не то, что вы хотите, если у вас есть столбец в одном наборе символов (например, latin1) но сохраненные значения на самом деле используют другой несовместимый набор символов (например, utf8). В этом случае вы должны сделать следующее для каждого такого столбца:

    ALTER TABLE t1 CHANGE c1 c1 BLOB;
    ALTER TABLE t1 CHANGE c1 c1 НАСТРОЙКА ХАРАКТЕРА ТЕКСТА utf8;
    

    Причина, по которой это работает, заключается в том, что нет конвертации при конвертации в или из BLOB колонны.

  • 0x3f указывает на то, что база данных действительно содержит буквенный символ ? и ваши исходные данные были потеряны: это не легко сделать, поскольку MySQL обычно выдает ошибку 1366, если неявное транскодирование приводит к потере данных. Возможно, в вашем выражении вставки было какое-то явное транскодирование?

    В этом случае вам необходимо преобразовать кодировку хранилища в подходящий формат, а затем обновить или заново вставить данные:

    ALTER TABLE foo CONVERT TO utf8;
    UPDATE foo SET name = _utf8 '爆笑笑話' WHERE bar = 'foobar';
    
Другие вопросы по тегам