วิธีทำให้ MySQL จัดการ UTF-8 อย่างถูกต้อง


102

หนึ่งในคำตอบสำหรับคำถามที่ฉันถามเมื่อวานนี้แนะนำว่าฉันควรตรวจสอบให้แน่ใจว่าฐานข้อมูลของฉันสามารถรองรับอักขระ UTF-8 ได้อย่างถูกต้อง ฉันจะทำสิ่งนี้กับ MySQL ได้อย่างไร


4
ฉันหวังเป็นอย่างยิ่งว่าเราจะได้รับคำตอบที่ครอบคลุมครอบคลุม MySQL เวอร์ชันต่างๆความเข้ากันไม่ได้ ฯลฯ
Edward Z. Yang


1
@ EdwardZ.Yang - เปิดตัว MySQL 4.1 CHARACTER SETs; 5.1.24 ยุ่งกับการเรียงลำดับของ German sharp-s (ß) ซึ่งได้รับการแก้ไขโดยการเพิ่มการเปรียบเทียบอีกครั้งใน 5.1.62 (เนื้อหาทำให้แย่ลง) 5.5.3 กรอก utf8 ด้วยชุดอักขระใหม่ utf8mb4
Rick James

1
คำถามนี้ค่อนข้างเหมือนกันกับคำถามนี้ .. โปรดดูที่stackoverflow.com/questions/3513773/…
Nyein Aung

ควรชี้ให้เห็นว่าคำตอบเหล่านี้ส่วนใหญ่ผิดธรรมดา ห้ามใช้utf8. รองรับอักขระไม่เกิน 3 ไบต์เท่านั้น ชุดตัวอักษรที่ถูกต้องที่คุณควรใช้ใน MySQL utf8mb4เป็น
Brendan Byrd

คำตอบ:


89

อัปเดต:

คำตอบสั้น ๆ - คุณควรใช้utf8mb4ชุดอักขระและการutf8mb4_unicode_ciเรียงลำดับเกือบตลอดเวลา

ในการแก้ไขฐานข้อมูล:

ALTER DATABASE dbname CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

ดู:

คำตอบเดิม:

MySQL 4.1 ขึ้นไปมีชุดอักขระเริ่มต้นเป็น UTF-8 คุณสามารถตรวจสอบได้ในmy.cnfไฟล์ของคุณอย่าลืมตั้งค่าทั้งไคลเอนต์และเซิร์ฟเวอร์ ( default-character-setและcharacter-set-server)

หากคุณมีข้อมูลที่ต้องการแปลงเป็น UTF-8 ให้ถ่ายโอนข้อมูลฐานข้อมูลของคุณและนำเข้ากลับเป็น UTF-8 โดยให้แน่ใจว่า:

  • ใช้SET NAMES utf8ก่อนที่คุณจะสอบถาม / แทรกลงในฐานข้อมูล
  • ใช้DEFAULT CHARSET=utf8เมื่อสร้างตารางใหม่
  • ณ จุดนี้ไคลเอนต์ MySQL และเซิร์ฟเวอร์ของคุณควรอยู่ใน UTF-8 (ดูmy.cnf) จำภาษาที่คุณใช้ (เช่น PHP) ต้องเป็น UTF-8 ด้วย PHP บางเวอร์ชันจะใช้ไลบรารีไคลเอ็นต์ MySQL ของตนเองซึ่งอาจไม่ทราบว่าเป็น UTF-8

หากคุณต้องการย้ายข้อมูลที่มีอยู่อย่าลืมสำรองข้อมูลก่อน! การสับข้อมูลแปลก ๆ มากมายอาจเกิดขึ้นได้เมื่อสิ่งต่างๆไม่เป็นไปตามแผน!

แหล่งข้อมูลบางส่วน:


29
ความเข้าใจของฉันคือutf8ภายใน MySQL อ้างถึงชุดย่อยของ Unicode เต็มรูปแบบเท่านั้น คุณควรใช้utf8mb4แทนเพื่อบังคับให้สนับสนุนเต็มที่ ดูmathiasbynens.be/notes/mysql-utf8mb4 "เป็นเวลานานที่ฉันใช้ชุดอักขระ utf8 ของ MySQL สำหรับฐานข้อมูลตารางและคอลัมน์โดยสมมติว่าแมปกับการเข้ารหัส UTF-8 ที่อธิบายไว้ข้างต้น"
Aaron McDaid

7
MySQL ไม่เคยมีชุดอักขระเริ่มต้นของ UTF-8 4.1 และ 5.x จนถึง 5.7 ล่าสุดใช้ทั้งหมดlatin1และlatin1_swedish_ciสำหรับชุดอักขระเริ่มต้นและการเปรียบเทียบ ดูหน้า "Server Character Set and Collation" ในคู่มือ MySQL สำหรับการยืนยัน: dev.mysql.com/doc/refman/5.1/en/charset-server.html
Animism

2
@TimTisdall คุณไม่ต้องกังวลกับutf8mb4การใช้พื้นที่เก็บข้อมูลเพิ่มเติมเมื่อข้อความส่วนใหญ่เป็น ASCII แม้ว่าcharสตริง preallocated, varcharสตริงไม่ได้ - ดูไม่กี่บรรทัดสุดท้ายในหน้าเอกสารฉบับนี้ ตัวอย่างเช่นchar(10)จะสงวนไว้ในแง่ร้าย 40 ไบต์ภายใต้ utf8mb4 แต่varchar(10)จะจัดสรรไบต์ให้สอดคล้องกับการเข้ารหัสความยาวตัวแปร
Kevin A. Naudé

1
@ เควินฉันคิดว่าคุณอ่านผิด ฉันคิดว่าความยาวแถวสูงสุดคือ 64k คุณสามารถสร้างฟิลด์ utf8mb4 ได้เพียง 1/4 จากนั้นเนื่องจากต้องจองพื้นที่ไว้ ดังนั้นแม้ว่าจะเป็น ASCII คุณสามารถแทรกอักขระได้ 16k เท่านั้น
Tim Tisdall

1
@TimTisdall โอ้คุณกำลังพูดถึงขอบเขตบน ใช่สิ่งเหล่านี้ต่ำกว่า โชคดีที่ mysql เวอร์ชันปัจจุบันจะอัปเกรดจากvarchar(n)เป็นtextประเภทข้อมูลโดยอัตโนมัติหากคุณพยายามแก้ไขvarchar(n)ฟิลด์ให้ใหญ่กว่าขนาดไบต์ที่เป็นไปได้ (ในขณะที่ออกคำเตือน) ดัชนีจะมีขอบเขตบนของกรณีที่เลวร้ายที่สุดต่ำกว่าด้วยและอาจทำให้เกิดปัญหาอื่น ๆ
Kevin A. Naudé

44

หากต้องการทำให้ 'ถาวร' ในmy.cnf:

[client]
default-character-set=utf8
[mysqld]
character-set-server = utf8

ในการตรวจสอบไปที่ไคลเอนต์และแสดงตัวแปร:

SHOW VARIABLES LIKE 'character_set%';

ตรวจสอบว่าพวกเขาทั้งหมดutf8ยกเว้น..._filesystemที่ควรจะเป็นbinaryและ..._dirชี้ไปที่ใดที่หนึ่งในการติดตั้ง MySQL


มันใช้ไม่ได้ในกรณีของฉัน แต่ฉันสร้างไฟล์ my.cf ใน / etc ด้วยเนื้อหาที่กำหนดอยู่ดี ฉันใช้create table my_name(field_name varchar(25) character set utf8);
Marek Bar

"แสดงตัวแปรที่ชอบ" character_set% ";" คำสั่งเปิดเผยปัญหาเกี่ยวกับการเชื่อมต่อของฉัน ขอบคุณ!
javsmo

1
สิ่งนี้ไม่ถูกต้อง สิ่งที่ MySQL เรียกutf8ไม่ใช่ UTF-8 แบบ "เต็ม"
TWR Cole

32

MySQL 4.1 ขึ้นไปมีชุดอักขระเริ่มต้นที่เรียกใช้utf8แต่จริงๆแล้วเป็นเพียงชุดย่อยของ UTF-8 (อนุญาตให้ใช้อักขระสามไบต์เท่านั้นและเล็กกว่า)

ใช้utf8mb4เป็นชุดอักขระของคุณหากคุณต้องการ UTF-8 แบบ "เต็ม"


5
เห็นด้วยอย่างแน่นอนนี่เป็นคำตอบเดียวที่ถูกต้อง utf8ไม่รวมอักขระเช่นอีโมติคอน utf8mb4ทำ. ตรวจสอบข้อมูลเพิ่มเติมเกี่ยวกับวิธีการอัปเดตได้ที่: mathiasbynens.be/notes/mysql-utf8mb4
jibai31

@Basti - ถูกต้องที่สุด (latin1 เป็นค่าเริ่มต้นจนกระทั่งเมื่อไม่นานมานี้) และไม่สมบูรณ์ (ไม่ได้กล่าวถึงการแทรก / การเลือกข้อมูลที่เข้ารหัส utf8 อย่างถูกต้องหรือการแสดงใน html)
Rick James

ด้วยความเคารพ @RickJames บาสตี้พูดว่า "จนถึงตอนนี้" - ฉันจำไม่ได้ว่าเห็นคำตอบของคุณเมื่อฉันโพสต์สิ่งนี้
TWR Cole

อนิจจามีอาการที่แตกต่างกันอย่างชัดเจนประมาณ 5 ประการของปัญหา utf8 และ 4 สิ่งที่โปรแกรมเมอร์ทำผิดเพื่อก่อให้เกิดปัญหา คำตอบส่วนใหญ่ชี้ให้เห็นเพียงสิ่งเดียวที่อาจต้องแก้ไข คำถามเดิมเป็นคำถามกว้าง ๆ ดังนั้นคำตอบจึงต้องการทั้ง 4 ข้อบางที Basti อาจคุ้นเคยกับอาการหนึ่งซึ่งแง่มุมหนึ่งของคุณเป็นวิธีแก้ปัญหา
Rick James

8
นอกจากนี้ฉันอยากจะหยุดสักครู่และให้ทีม MySQL มองเห็นได้ดีและยาก o_o WTF พวกคุณคิดยังไง? คุณรู้หรือไม่ว่าคุณสร้างความสับสนมากแค่ไหนโดยการสร้าง codepage ในโปรแกรมของคุณชื่อ "utf8" ที่ไม่ใช่ UTF-8 จริงๆ ไอ้เหี้ย </rant>
TWR Cole

20

คำตอบสั้น ๆ : ใช้utf8mb4ใน 4 ที่:

  • ไบต์ในไคลเอนต์ของคุณคือ utf8 ไม่ใช่ latin1 / cp1251 / etc
  • SET NAMES utf8mb4 หรือสิ่งที่เทียบเท่าเมื่อสร้างการเชื่อมต่อของไคลเอนต์กับ MySQL
  • CHARACTER SET utf8mb4 บนตาราง / คอลัมน์ทั้งหมด - ยกเว้นคอลัมน์ที่เคร่งครัด ascii / hex / country_code / zip_code / etc
  • <meta charset charset=UTF-8>หากคุณกำลังแสดงผลเป็น HTML (ใช่การสะกดแตกต่างกันที่นี่)

ข้อมูลเพิ่มเติม ;
UTF8 ตลอดทาง

ลิงก์ด้านบนระบุ "คำตอบตามรูปแบบบัญญัติโดยละเอียดจำเป็นต้องใช้เพื่อจัดการกับข้อกังวลทั้งหมด" - มีการ จำกัด พื้นที่ในฟอรัมนี้

แก้ไข

นอกจากจะCHARACTER SET utf8mb4มีอักขระ "ทั้งหมด" ของโลกแล้วCOLLATION utf8mb4_unicode_520_ciยังมีการจัดเรียงแบบ 'ที่ดีที่สุดรอบด้าน' ที่จะใช้อีกด้วย (นอกจากนี้ยังมีการจัดเรียงภาษาตุรกีสเปน ฯลฯ สำหรับผู้ที่ต้องการความแตกต่างในภาษาเหล่านั้น)


ลิงค์ใหม่ของฉันเกี่ยวกับวิธีการดีบักปัญหา utf8 จากผลลัพธ์ที่คุณได้รับ
Rick James

ทำไม unicode_520_ci ถึงไม่ดีที่สุด: stackoverflow.com/a/49982378/62202
Louis

@ หลุยส์ - และในขณะที่ฉันบอกเป็นนัยว่าผู้ใช้ภาษาสเปนและตุรกี (รวมทั้งโปแลนด์) อาจไม่พอใจ "ดีที่สุดในทุกด้าน" มีแนวโน้มที่จะทำร้ายทุกคน MySQL 8.0 มีแม้กระทั่งใหม่ "ดีที่สุด" เปรียบเทียบ: utf8mb4_0900_ai_ci อนิจจาอีกครั้ง L = Ł
Rick James

4

ชุดอักขระเป็นคุณสมบัติของฐานข้อมูล (ค่าเริ่มต้น) และตาราง คุณสามารถดูได้ (คำสั่ง MySQL):

show create database foo; 
> CREATE DATABASE  `foo`.`foo` /*!40100 DEFAULT CHARACTER SET latin1 */

show create table foo.bar;
> lots of stuff ending with
> ) ENGINE=InnoDB AUTO_INCREMENT=252 DEFAULT CHARSET=latin1

กล่าวอีกนัยหนึ่ง; มันค่อนข้างง่ายในการตรวจสอบชุดฐานข้อมูลของคุณหรือเปลี่ยนแปลง:

ALTER TABLE `foo`.`bar` CHARACTER SET utf8;

1
สิ่งนี้ไม่ถูกต้อง สิ่งที่ MySQL เรียกutf8ไม่ใช่ UTF-8 แบบ "เต็ม"
TWR Cole

3

หากต้องการเปลี่ยนการเข้ารหัสชุดอักขระเป็น UTF-8 สำหรับฐานข้อมูลให้พิมพ์คำสั่งต่อไปนี้ที่พร้อมต์ mysql> ใช้ALTER DATABASE.. แทนที่ DBNAME ด้วยชื่อฐานข้อมูล:

ALTER DATABASE DBNAME CHARACTER SET utf8 COLLATE utf8_general_ci;

คำถามนี้ซ้ำกันจะแปลงชุดอักขระฐานข้อมูล MySQL ทั้งหมดและการเปรียบเทียบเป็น UTF-8 ได้อย่างไร


2

ฉันติดตามวิธีแก้ปัญหาของ Javier แต่ฉันเพิ่มบรรทัดที่แตกต่างกันใน my.cnf:

[myslqd]
skip-character-set-client-handshake
collation_server=utf8_unicode_ci
character_set_server=utf8 

ฉันพบแนวคิดนี้ที่นี่: http://dev.mysql.com/doc/refman/5.0/th/charset-server.htmlในความคิดเห็นของผู้ใช้คนแรก / คนเดียวที่ด้านล่างของหน้า เขากล่าวว่าการจับมือแบบข้ามอักขระกำหนดลูกค้ามีความสำคัญ


คำตอบที่ไม่มีใครรักและไม่มีคะแนนเป็นสิ่งเดียวที่ช่วยฉันได้! ดังนั้นมันจึงได้รับการโหวตของฉันนั่นก็แน่นอน skip-character-set-client-handshakeเป็นกุญแจสำคัญ
Marcus


0

ตั้งค่าของคุณdatabase collationเพื่อUTF-8 ใช้table collationกับค่าเริ่มต้นของฐานข้อมูล


-1

คำตอบของคุณคือคุณสามารถกำหนดค่าโดยการตั้งค่า MySql ในคำตอบของฉันอาจมีบางอย่างที่ไม่อยู่ในบริบท แต่สิ่งนี้ก็เป็นความช่วยเหลือสำหรับคุณเช่นกัน
วิธีกำหนดค่าCharacter SetและCollation .

สำหรับแอปพลิเคชันที่จัดเก็บข้อมูลโดยใช้ชุดอักขระ MySQL เริ่มต้นและการเรียง ( latin1, latin1_swedish_ci) ไม่จำเป็นต้องมีการกำหนดค่าพิเศษ หากแอปพลิเคชันต้องการการจัดเก็บข้อมูลโดยใช้ชุดอักขระหรือการเรียงลำดับอื่นคุณสามารถกำหนดค่าข้อมูลชุดอักขระได้หลายวิธี:

  • ระบุการตั้งค่าอักขระต่อฐานข้อมูล ตัวอย่างเช่นแอปพลิเคชันที่ใช้ฐานข้อมูลเดียวอาจต้องการutf8ในขณะที่แอปพลิเคชันที่ใช้ฐานข้อมูลอื่นอาจต้องใช้ sjis
  • ระบุการตั้งค่าอักขระเมื่อเริ่มต้นเซิร์ฟเวอร์ สิ่งนี้ทำให้เซิร์ฟเวอร์ใช้การตั้งค่าที่กำหนดสำหรับแอปพลิเคชันทั้งหมดที่ไม่ได้ทำการจัดเตรียมอื่น ๆ
  • ระบุการตั้งค่าอักขระในเวลากำหนดค่าหากคุณสร้าง MySQL จากซอร์ส สิ่งนี้ทำให้เซิร์ฟเวอร์ใช้การตั้งค่าที่กำหนดสำหรับแอปพลิเคชันทั้งหมดโดยไม่ต้องระบุเมื่อเริ่มต้นเซิร์ฟเวอร์

ตัวอย่างที่แสดงไว้ที่นี่สำหรับคำถามของคุณในการตั้งค่าชุดอักขระ utf8 นอกจากนี้ยังตั้งค่าการเปรียบเทียบเพื่อประโยชน์มากขึ้น ( utf8_general_cicollation`)

ระบุการตั้งค่าอักขระต่อฐานข้อมูล

  CREATE DATABASE new_db
  DEFAULT CHARACTER SET utf8
  DEFAULT COLLATE utf8_general_ci;

ระบุการตั้งค่าอักขระเมื่อเริ่มต้นเซิร์ฟเวอร์

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

ระบุการตั้งค่าอักขระในเวลากำหนดค่า MySQL

shell> cmake . -DDEFAULT_CHARSET=utf8 \
           -DDEFAULT_COLLATION=utf8_general_ci

หากต้องการดูค่าของชุดอักขระและตัวแปรระบบการเปรียบเทียบที่ใช้กับการเชื่อมต่อของคุณให้ใช้คำสั่งเหล่านี้:

SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';

นี่อาจเป็นคำตอบที่ยาว แต่มีทุกวิธีที่คุณสามารถใช้ได้ หวังว่าคำตอบของฉันจะเป็นประโยชน์สำหรับคุณ สำหรับข้อมูลเพิ่มเติมhttp://dev.mysql.com/doc/refman/5.7/en/charset-applications.html


-2

SET NAMES UTF8

นี่คือเคล็ดลับ


2
ในขณะที่ใช้SET NAMES UTF8(หรือUTF8mb4) ถูกต้องคุณจะไม่อธิบายว่ามันทำอะไร (ชุดอักขระที่ใช้สำหรับการเชื่อมต่อนี้) "นี่เป็นเคล็ดลับ" ดูเหมือนจะช่วยแก้ปัญหาได้ (ทำให้ MySQL จัดการ UTF-8 ได้อย่างถูกต้อง) แต่ฐานข้อมูล MySQL จำนวนมากถูกตั้งค่าเป็น latin1 ตามค่าเริ่มต้นดังนั้นจะไม่ทำให้เป็นวิธีแก้ปัญหาที่เหมาะสม ฉันจะเปลี่ยนชุดอักขระเริ่มต้นและชุดอักขระของตารางเป็น utf8mb4 จริงๆแล้วคำตอบนี้ค่อนข้างไม่สมบูรณ์ดังนั้นฉันจึงลดลง
พื้นฐาน 6

-2

การเชื่อมต่อฐานข้อมูลกับ UTF-8

$connect = mysql_connect('$localhost','$username','$password') or die(mysql_error());
mysql_set_charset('utf8',$connect);
mysql_select_db('$database_name','$connect') or die(mysql_error());

-3

ตั้งค่าการเชื่อมต่อฐานข้อมูลของคุณเป็น UTF8:

  if($handle = @mysql_connect(DB_HOST, DB_USER, DB_PASS)){          
         //set to utf8 encoding
         mysql_set_charset('utf8',$handle);
  }

หากใช้ PHP อย่าใช้mysql_*อินเทอร์เฟซที่เลิกใช้แล้ว สลับไปหรือmysqli_* PDO
Rick James

-3

ก็สามารถที่จะหาทางแก้ไข เรียกใช้สิ่งต่อไปนี้ตามที่ระบุไว้ที่http://technoguider.com/2015/05/utf8-set-up-in-mysql/

SET NAMES UTF8;
set collation_server = utf8_general_ci;
set default-character-set = utf8;
set init_connect = SET NAMES utf8′;
set character_set_server = utf8;
set character_set_client = utf8;

สองบรรทัดสุดท้ายซ้ำซ้อนเนื่องจากบรรทัดแรกรวมไว้แล้ว: dev.mysql.com/doc/refman/5.0/th/charset-connection.html
DanielM

ยังไม่ใช่โซลูชันที่สมบูรณ์ CHARACTER SET utf8คอลัมน์ต้อง rootจะไม่ดำเนินการที่สำคัญinit_connectทั้งหมด
Rick James
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.