Недавно я столкнулся с ошибкой, когда пытался сохранить строку UTF-8 в MariaDB, закодированную в «utf8» через Rails, и получил странную ошибку:
Incorrect string value: ‘\xF0\x9F\x98\x83 <…’ for column ‘summary’ at row 1
Я использую клиент с кодировкой UTF-8, сервер также имеет кодировку UTF-8, как и база данных, и даже сохраняемая строка «<... utf-8.>
Суть в том, что «utf8» MySQL на самом деле не является UTF-8.
«utf8» поддерживает только до трех байтов на символ, в то время как настоящий UTF-8 поддерживает до четырех байтов на символ.
MySQL так и не исправил эту ошибку, они выпустили набор символов под названием «utf8mb4» в 2010 году, который обошел проблему.
Конечно, они не рекламировали новый набор символов (вероятно, потому что ошибка их смущала), так что в сети до сих пор советуют разработчикам использовать «utf8», но все эти предложения неверны.
Краткое резюме выглядит следующим образом:
- MySQL «utf8mb4» на самом деле является «UTF-8».
- MySQL "utf8" - это "собственная кодировка", которая может кодировать не так много символов Unicode.
Позвольте мне пояснить: все пользователи MySQL и MariaDB, использующие «utf8», должны вместо этого использовать «utf8mb4» и никогда больше не использовать «utf8».
Так что же такое кодировка? Что такое UTF-8?
Все мы знаем, что компьютеры используют 0 и 1 для хранения текста. Например, символ «С» хранится как «01000011», тогда компьютеру необходимо пройти два шага при отображении этого символа:
Компьютер читает «01000011» и получает число 67, потому что 67 закодировано как «01000011».
Компьютер искал 67 в наборе символов Unicode и нашел «C».
такой же:
- Мой компьютер сопоставляет «C» с 67 в наборе символов Unicode.
- Мой компьютер кодирует 67 как «01000011» и отправляет его на веб-сервер.
Почти все веб-приложения используют набор символов Unicode, потому что нет причин использовать какой-либо другой набор символов.
Набор символов Unicode содержит миллионы символов. Простейшей кодировкой является UTF-32, использующая 32 бита на символ. Сделать это проще всего, потому что компьютеры всегда воспринимали 32 бита как числа, а компьютеры лучше всего умеют работать с числами. Но проблема в том, что это пустая трата места.
UTF-8 может сэкономить место.В UTF-8 для символа «C» требуется всего 8 бит, а для некоторых менее часто используемых символов, таких как «», требуется 32 бита. Другие символы могут использовать 16 или 24 бита. Такая статья, если она закодирована в UTF-8, занимает всего около четверти пространства UTF-32.
Набор символов MySQL "utf8" несовместим с другими программами, и его так называемый "" действительно может быть куском...
Краткая история MySQL
Почему разработчики MySQL делают «utf8» недействительным? Возможно, мы сможем найти ответ в журнале коммитов.
MySQL поддерживает UTF-8, начиная с версии 4.1, которая была выпущена в 2003 году, а используемый сегодня стандарт UTF-8 (RFC 3629) появился позже.
Устаревший стандарт UTF-8 (RFC 2279) поддерживает до 6 байтов на символ. 28 марта 2002 г. разработчики MySQL использовали RFC 2279 в первой предварительной версии MySQL 4.1.
В сентябре того же года в исходный код MySQL внесли корректировку: «UTF8 теперь поддерживает только последовательности до 3 байт».
Кто отправил этот код? Зачем ему это делать? Этот вопрос неизвестен. После перехода на Git (MySQL начинался с BitKeeper) многие имена коммиттеров в кодовой базе MySQL были потеряны. В списке рассылки за сентябрь 2003 г. также не было никакой подсказки, объясняющей это изменение.
Но я могу попытаться угадать.
В 2002 году MySQL приняла решение: если пользователи могут гарантировать, что каждая строка таблицы данных использует одинаковое количество байтов, то MySQL может добиться значительного повышения производительности.
Для этого пользователю необходимо определить текстовый столбец как «CHAR», каждый столбец «CHAR» всегда имеет одинаковое количество символов. Если количество вставленных символов меньше определенного числа, MySQL дополнит пробелами, и если вставленные символы превысят определенное количество, лишняя часть будет усечена.
Разработчики MySQL сначала попробовали UTF-8 с 6 байтами на символ, CHAR(1) с 6 байтами, CHAR(2) с 12 байтами и так далее.
Надо сказать, что их первоначальное поведение было правильным, но, к сожалению, эта версия не была выпущена.
Но это написано в документации, и широко распространено, и все, кто знает UTF-8, согласны с тем, что написано в документации.
Однако ясно, что разработчики или поставщики MySQL обеспокоены тем, что пользователи будут делать две вещи:
- Используйте CHAR для определения столбца (CHAR сейчас устарел, но тогда было быстрее использовать CHAR в MySQL, но не с 2005 года).
- Установите кодировку столбцов CHAR на «utf8».
Я предполагаю, что разработчики MySQL пытались помочь пользователям, которые хотели беспроигрышный вариант в пространстве и скорости, но они напортачили с кодировкой «utf8».
Вот и получается, что победителей нет. Пользователи, которые хотят выиграть в пространстве и скорости, когда они используют столбцы CHAR «utf8», на самом деле используют больше места и медленнее, чем ожидалось. И пользователи, которые хотят корректности, не могут сохранять символы типа "", когда они используют кодировку "utf8".
После того, как этот недопустимый набор символов был выпущен, MySQL не смогла его исправить, и всем пользователям потребовалось перестроить свои базы данных. В конце концов, MySQL перевыпустил «utf8mb4» в 2010 году для поддержки истинной UTF-8.
Почему эта штука сводит людей с ума
Я был зол на неделю из-за этой проблемы. Меня одурачил "utf8" и я потратил много времени на поиск этой ошибки. Но я не должен быть единственным, почти все статьи в Интернете рассматривают «utf8» как настоящую UTF-8.
«utf8» можно рассматривать только как проприетарный набор символов, он приносит нам новые проблемы, но не решен.
Суммировать
Если вы используете MySQL или MariaDB, не используйте кодировку «utf8», вместо этого используйте «utf8mb4». здесь(Матиас, не груби, не голодай /notes/MySQL…
Английский оригинал:
medium.com/@Адам Хупер…
Добро пожаловать, чтобы обратить внимание на мою общедоступную учетную запись WeChat «Code Farmer Breakthrough», поделиться Python, Java, большими данными, машинным обучением, искусственным интеллектом и другими технологиями, обратить внимание на улучшение технологии кодового фермера, прорыв в карьере, переход к мышлению, более 200 000 код фермера рост и зарядка в первую очередь стоять, расти вместе с вами, у кого есть мечты