Вы получаете поддержку от ИТ-администратора технической компании, который говорит, что некоторые из его важных данных не могут быть сохранены в продукте, который вы развернули на его серверах неделю назад. Его пользователи видят общую ошибку из приложения. Около 30 из его 500 пользователей испытывают эту проблему и не могут сохранить данные в приложении.
После короткого 15-минутного сеанса отладки вы можете видеть, что данные передаются со стороны клиента, принимаются на внутреннем сервере и запрос на вставку запускается в базу данных. Но все же нет данных в базе данных.
Хм .. теперь стало интересно. Вы закатываете рукава, улыбаетесь на лице, очки на глазах и начинаете расследование (ну, может быть, просто начнете расследование без всяких модных аксессуаров).
Глядя на журналы, выясняется, что для конкретных входных данных MySQL отказался добавлять данные в базу данных. MySQL сообщает об ошибке:
Incorrect string value: ‘\xF0\x9F\x98\x81…’ for column ‘data’ at row 1
Это хороший совет, но почему? Что это вообще значит? Как это может быть неправильно? Ну, мы начали исследовать эту строку и обнаружил, что первые 4 байта объединяют определенный смайлик в UTF8. Таким образом, это означает, что в этом конкретном входе каждый символ, вероятно, закодирован как 4 байта.
Мы попытались воспроизвести эту проблему с помощью другой строки, символы которой закодированы по 1/2 байта на символ. Оказалось, что это происходит только тогда, когда каждый символ в данных был объединен в 4 байта. Набор символов, который я использовал в базе данных, – UTF8, который должен поддерживать 4 байта (верно?), Так что не так?
Ну, оказывается, мы были не правы. Мы узнали, что MySQL решил, что UTF-8 может содержать только 3 байта на символ. Зачем? Нет веской причины, по которой мы можем найти документальное подтверждение где угодно. Спустя несколько лет, когда был выпущен MySQL 5.5.3, они представили новую кодировку utf8mb4 , которая на самом деле является реальной 4-байтовой кодировкой utf8, которую вы знаете и любите.
Если вы используете MySQL в любом варианте (MySQL, MariaDB, PerconaDB и т. д.), убедитесь, что вы знаете свои кодировки. Мы бы порекомендовали установить кодировку MySQL на utf8mb4. Никогда не используйте utf8 в MySQL, нет веских причин для этого (если вы не любите отслеживать ошибки, связанные с кодировкой).
Так что теперь мы должны были решить эту проблему. Как мы рекомендовали выше, мы хотели использовать utf8mb4 и удалить старый utf8. Для этого использовали следующие операторы ALTER. Пожалуйста, НЕ просто копируйте и вставляйте их. Вы должны убедиться, что вы понимаете каждый из них и соответственно скорректировать их.
# Запустите это один раз для каждой схемы (замените database_name на имя схемы) ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; # Запустите это один раз для каждой таблицы (замените table_name именем таблицы) ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # Выполните это для каждого столбца (замените имя таблицы, column_name, тип столбца, максимальную длину и т. д.) ALTER TABLE table_name CHANGE column_name column_name VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Обратите внимание, что вам придется учитывать последствия увеличения размера столбца с 3 байтов на символ до 4. Например, индексы MySQL ограничены 768 байтами. Это означает, что если вы увеличите VARCHAR (255) с 3 байт на символ до 4 байт на символ, вы больше не будете соблюдать этот предел.
В заключение убедитесь, что вы читаете о внутренностях каждого решения, которое вы принимаете с MySQL. Да, и используйте utf8mb4 вместо utf8, даже не задумываясь об этом.