воскресенье, 26 августа 2012 г.

Проблема с кодировками в MySQL

Не смотря на то, что в настоящее время почти повсеместно используется кодировка UTF-8, ещё случаются иногда курьёзные случаи с кодировками.

Недавно столкнулся с проблемой такого рода. Сервер базы данных работал в latin1. Кодировка базы данных и всех её таблиц - UTF-8. На веб-сервере работало приложение на PHP, которое само по себе оперировало информацией в базе данных тоже в кодировке UTF-8. Беда в том, что в переменных окружения веб-сервера тоже стояла кодировка latin1. Сервер базы данных общался с клиентом базы данных, думая что оба они работают с информацией в кодировке latin1, хотя по факту информация была в UTF-8. Соответственно, никаких проблем не наблюдалось до тех пор, пока к серверу баз данных не подключился клиент, который захотел общаться в кодировке, отличной от latin1. Клиент получал что угодно, но только не текст в запрошенной кодировке.

Чтобы исправить ситуацию, в веб-приложении пришлось сразу после подключения к базе данных задавать желаемую кодировку запросом "SET CHARACTER SET 'UTF8'". Осталось перекодировать данные.

Сначала снимем дамп с базы данных, запросив данные в кодировке latin1. На самом деле они сольются в той кодировке, которой пользовалось веб-приложение. В данном случае это UTF-8.
$ mysqldump --default-character-set=latin1 -uroot -p base | grep -vE "^\/\*" > base.sql
Из дампа попутно удаляются все строки, начинающиеся с символов "/*" - это директивы, задающие настройки кодировок при импорте-экспорте.

Теперь запустим консольный клиент, и создадим пустую базу данных в кодировке UTF-8:
$ mysql -uroot -p
> create database base2 charset utf8;
Осталось выбрать кодировку, в которой хранится информация в дампе и залить в новую базу данных ранее сохранённый дамп. В нашем случае это опять UTF-8.
> charset utf8;
> use base2;
> source base.sql
Теперь можно выбирать в клиенте ту кодировку, которая стоит в терминале, и видеть текст. В моём случае в терминале была настроена кодировка KOI8-R:
> charset koi8r;
> select * from table_name limit 10;
Если всё сделано правильно, можно повторить восстановление дампа уже в основную базу и удалить тестовую базу данных:
> drop database base;
> create database base charset utf8;
> charset utf8;
> source base.sql
> drop database base2;

Комментариев нет: