Требуется ли «SET CHARACTER SET utf8»?

Я переписываю наш класс базы данных (основанный на PDO) и застрял в этом. Меня учили использовать SET NAMES utf8 и SET CHARACTER SET utf8 при работе с UTF-8 в PHP и MySQL.

В PDO я теперь хочу использовать параметр PDO::MYSQL_ATTR_INIT_COMMAND , но он поддерживает только один запрос.

SET CHARACTER SET utf8 ли SET CHARACTER SET utf8 ?

С помощью SET CHARACTER SET utf8 после использования SET NAMES utf8 самом деле сбросит character_set_connection и collation_connection на
@@character_set_database и @@collation_database соответственно.

В руководстве указано, что

  • SET NAMES x эквивалентен

     SET character_set_client = x; SET character_set_results = x; SET character_set_connection = x; 
  • и SET CHARACTER SET x эквивалентно

     SET character_set_client = x; SET character_set_results = x; SET collation_connection = @@collation_database; 

тогда как SET collation_connection = x также внутренне выполняет SET character_set_connection = <<character_set_of_collation_x>> и SET character_set_connection = x внутренне также выполняет SET collation_connection = <<default_collation_of_character_set_x .

Таким образом, вы переустанавливаете character_set_connection на @@character_set_database и collation_connection на @@collation_database . В руководстве объясняется использование этих переменных:

Какой набор символов должен сервер перевести инструкцию после получения?

Для этого сервер использует системные переменные character_set_connection и collation_connection. Он преобразует утверждения, отправленные клиентом от character_set_client к character_set_connection (за исключением строковых литералов, у которых есть интродуктор, такой как _latin1 или _utf8). collation_connection важна для сравнения литеральных строк. Для сравнения строк со значениями столбцов объединение collation_connection не имеет значения, поскольку столбцы имеют собственную сортировку, которая имеет более высокий приоритет сортировки.

Чтобы подвести итог, процедура кодирования / перекодирования MySQL используется для обработки запроса, а его результаты – многоступенчатая:

  1. MySQL обрабатывает входящий запрос как закодированный в character_set_client .
  2. MySQL перекодирует оператор из character_set_client в character_set_connection
  3. при сравнении значений строк с значениями столбцов MySQL перекодирует строковое значение из character_set_connection в набор символов данного столбца базы данных и использует сортировку столбцов для сортировки и сравнения.
  4. MySQL создает набор результатов, закодированный в character_set_results (это включает в себя данные результата, а также метаданные результатов, такие как имена столбцов и т. Д.),

Таким образом, может быть, что SET CHARACTER SET utf8 не будет достаточным для обеспечения полной поддержки UTF-8. Подумайте о наборе символов базы данных по умолчанию latin1 и столбцах, определенных с помощью utf8 charset, и выполните шаги, описанные выше. Поскольку latin1 не может охватить все символы, которые могут покрывать UTF-8, вы можете потерять информацию о символе на шаге 3 .

  • Шаг 3 : Учитывая, что ваш запрос закодирован в UTF-8 и содержит символы, которые не могут быть представлены с помощью latin1 , эти символы будут потеряны при перекодировании с utf8 на latin1 (набор символов базы данных по умолчанию), что приведет к сбою вашего запроса.

Поэтому я думаю, что можно с уверенностью сказать, что SET NAMES ... – это правильный способ справиться с проблемами набора символов. Хотя я мог бы добавить, что правильная настройка ваших переменных MySQL сервера (все обязательные переменные могут быть установлены статически в my.cnf ) освобождает вас от служебных накладных расходов дополнительного запроса, необходимого для каждого подключения.

Из руководства mysql :

SET CHARACTER SET аналогичен SET NAMES, но устанавливает character_set_connection и collation_connection в character_set_database и collation_database . Оператор SET CHARACTER SET x эквивалентен этим трех операторам:

 SET character_set_client = x; SET character_set_results = x; SET collation_connection = @@collation_database; 

Поскольку мне нужно поддерживать международные наборы символов, я всегда просто задавал набор символов полей типа текста при создании базы данных.

Я также всегда использовал UTF-8.

В PHP установлено то же самое:

 mb_internal_encoding( 'UTF-8' );