Именно тогда я начал строить YourQuote. Все работало нормально, все данные хранились в mysql. Пока я не понял, комментарии к тестовой публикации обрезались, когда кто-то вставлял в нее смайлик. Whattttt! Данные усечены, что происходит!
Было шокирующим видеть такие вещи, происходящие с использованием такой зрелой технологии. Мой стек был Django + Mysql. Это очень зрелые платформы, и они должны обрабатывать подобные случаи без сбоев. После некоторого исследования я узнал об этой оптимизации (говоря эвфемистически), сделанной mysql для хранения строк. Mysql поддерживает utf-8, но по умолчанию выделяет только 3 байта для хранения символа, что недостаточно, когда дело доходит до размера, необходимого для хранения китайского или японского символа.
В качестве предварительного условия я бы посоветовал вам иметь хорошее представление о наборах символов и кодировке символов. Вкратце: Нет смысла иметь строку, не зная, какую кодировку она использует. Обратитесь к этой блестящей статье Джоэла Спольски, чтобы подробно разобраться в концепции.
Подводя итог: не существует такого понятия, как простой текст, кодирование необходимо, чтобы понять, что означают данные. Юникод может занимать до 6 байтов для хранения символа.
Учитывая вышеупомянутый факт, конфигурация mysql по умолчанию для предоставления 3 байтов для символа не подходит для пользовательских приложений, в которых вы не можете контролировать строку ввода от пользователей. В защиту mysql можно сказать, что это можно рассматривать как оптимизацию для экономии места. Что ж, необходимо некоторое объяснение того, почему mysql делает это, и чтобы понять, что вы должны сначала знать, что mysql — это хранилище данных строки (а не хранилище данных столбца). Прочтите эту статью, чтобы понять разницу.
Несколько указателей на mysql:
- Индексы могут быть сформированы только на charField (у них есть ограничение на максимальный размер), но не на строковых / больших двоичных полях.
- Длинные строки / капли не сохраняются в строке. Сохраняется только указатель на них, на самом деле значение где-то еще.
Наконец, у нас есть все необходимые условия. Теперь мы знаем, что нам нужно более 3 байтов для хранения этих смайлов, иначе я бы не писал эту статью. Итак, остальная часть статьи будет охватывать шаги, необходимые для его реализации на вашем mysql-сервере.
1. Найдите файл my.cnf, он должен находиться в / etc / mysql (есть лучший способ иметь свои собственные файлы конфигурации mysql, но здесь это не обсуждается). Найдите раздел в квадратных скобках и измените переменную, указанную под ними, соответственно.
[клиент]
набор символов по умолчанию = utf8mb4
[mysql]
набор символов по умолчанию = utf8mb4
[mysqld]
рукопожатие набора символов клиента = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
2. Я использую django для своего приложения, поэтому эти настройки специфичны для него, но каждая структура имеет конфигурацию для подключения к серверу mysql. Измените соответственно.
БАЗЫ ДАННЫХ = {
‘default’: {
‘ENGINE’: ‘django.db.backends.mysql’,
‘NAME’: ‘my_db_name’,
‘USER’: ‘my_db_user’,
‘ПАРОЛЬ’: ‘my_db_pass’,
‘ОПЦИИ’: {‘charset’: ‘utf8mb4’}, # для уведомления
}
3. При создании базы данных укажите набор символов
создать базу данных my_db_name набор символов utf8mb4;
После этого запустите указанную ниже команду в оболочке mysql, чтобы проверить, все ли настроено правильно.
ПОКАЗАТЬ ПЕРЕМЕННЫЕ, ГДЕ имя_переменной, КАК «символ \ _set \ _%» ИЛИ имя_переменной, КАК «сопоставление%»;
Когда вы запустите эту команду, вы должны получить что-то вроде этого
| character_set_client | utf8mb4
| character_set_connection | utf8mb4
| character_set_database | utf8mb4
| character_set_filesystem | двоичный
| character_set_results | utf8mb4
| character_set_server | utf8mb4
| character_set_system | utf8
| character_sets_dir | / usr / share / mysql / charsets /
| collation_connection | utf8mb4_general_ci
| collation_database | utf8mb4_general_ci
| collation_database | utf8mb4_general_ci
Здесь стоит обратить внимание на utf8mb4. Эта кодировка указывает mysql хранить 4 байта для символа. Теперь mysql может обрабатывать символы, занимающие до 4 байтов, что решает нашу проблему и легко обрабатывает символы, такие как смайлик.
У этого есть как плюсы, так и минусы. Компромисс между хранилищем и гибкостью. Но поскольку в наши дни хранение не так дорого, принять это решение не так уж и сложно.
Оставляя примечания: проверьте Postgresql, он без проблем справился с utf-8.
PS: указанная выше функция доступна для mysql 5.5.3 и выше.
PPS: как насчет символов юникода, которые занимают более 4 байтов. Увидим это, когда столкнемся. Необязательно решать все проблемы прямо сейчас. Мы в порядке.
Оставьте комментарий, если вы сочтете это полезным.