Cách làm cho MySQL xử lý UTF-8 đúng cách


102

Một trong những câu trả lời cho câu hỏi mà tôi đã hỏi ngày hôm qua đề xuất rằng tôi nên đảm bảo rằng cơ sở dữ liệu của mình có thể xử lý các ký tự UTF-8 một cách chính xác. Làm cách nào tôi có thể làm điều này với MySQL?


4
Tôi thực sự hy vọng chúng tôi sẽ nhận được câu trả lời toàn diện, bao gồm các phiên bản MySQL khác nhau, sự không tương thích, v.v.
Edward Z. Yang


1
@ EdwardZ.Yang - MySQL 4.1 được giới thiệu CHARACTER SETs; 5.1.24 đã làm xáo trộn sự đối chiếu của chữ sharp-s (ß) của Đức, điều này đã được sửa lại bằng cách thêm một đối chiếu khác trong 5.1.62 (được cho là làm cho mọi thứ trở nên tồi tệ hơn); 5.5.3 đã điền utf8 bằng bộ ký tự mới utf8mb4.
Rick James,

1
Câu hỏi này là khá tương tự với trang này .. Hãy nhìn vào đó stackoverflow.com/questions/3513773/...
Nyein Aung

Cần phải chỉ ra rằng hầu hết các câu trả lời này hoàn toàn sai. Không sử dụng utf8. Nó chỉ hỗ trợ tối đa ký tự 3 byte. Bộ ký tự chính xác bạn nên sử dụng trong MySQL là utf8mb4.
Brendan Byrd

Câu trả lời:


89

Cập nhật:

Câu trả lời ngắn gọn - Bạn hầu như luôn phải sử dụng utf8mb4bảng mã và utf8mb4_unicode_ciđối chiếu.

Để thay đổi cơ sở dữ liệu:

ALTER DATABASE dbname CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Xem:

Câu trả lời gốc:

MySQL 4.1 trở lên có bộ ký tự mặc định là UTF-8. Bạn có thể xác minh điều này trong my.cnftệp của mình , hãy nhớ đặt cả máy khách và máy chủ ( default-character-setcharacter-set-server).

Nếu bạn có dữ liệu hiện có mà bạn muốn chuyển đổi sang UTF-8, hãy kết xuất cơ sở dữ liệu của bạn và nhập nó trở lại dưới dạng UTF-8, đảm bảo:

  • sử dụng SET NAMES utf8trước khi bạn truy vấn / chèn vào cơ sở dữ liệu
  • sử dụng DEFAULT CHARSET=utf8khi tạo bảng mới
  • tại thời điểm này, máy khách và máy chủ MySQL của bạn phải ở dạng UTF-8 (xem my.cnf). hãy nhớ rằng bất kỳ ngôn ngữ nào bạn sử dụng (chẳng hạn như PHP) cũng phải là UTF-8. Một số phiên bản PHP sẽ sử dụng thư viện máy khách MySQL của riêng chúng, thư viện này có thể không nhận biết được UTF-8.

Nếu bạn muốn di chuyển dữ liệu hiện có, hãy nhớ sao lưu trước! Rất nhiều dữ liệu bị cắt nhỏ kỳ lạ có thể xảy ra khi mọi thứ không diễn ra như kế hoạch!

Một số tài nguyên:


29
Sự hiểu biết của tôi là utf8bên trong MySQL chỉ đề cập đến một tập hợp con nhỏ của Unicode đầy đủ. Bạn nên sử dụng utf8mb4thay thế để buộc hỗ trợ đầy đủ. Xem mathiasbynens.be/notes/mysql-utf8mb4 "Trong một thời gian dài, tôi đã sử dụng bộ ký tự utf8 của MySQL cho cơ sở dữ liệu, bảng và cột, giả sử nó được ánh xạ tới mã hóa UTF-8 được mô tả ở trên."
Aaron McDaid,

7
MySQL chưa bao giờ có bộ ký tự mặc định là UTF-8. 4.1 và 5.x cho đến 5.7 mới nhất đều sử dụng latin1latin1_swedish_cicho bộ ký tự và đối chiếu mặc định. Hãy xem phần "Máy chủ Character Set và Collation" trang trong cuốn hướng dẫn MySQL để xác nhận: dev.mysql.com/doc/refman/5.1/en/charset-server.html
Animism

2
@TimTisdall Bạn không cần phải lo lắng về utf8mb4việc tốn thêm dung lượng khi hầu hết văn bản là ASCII. Mặc dù các charchuỗi được phân bổ trước nhưng các varcharchuỗi thì không - hãy xem vài dòng cuối cùng trên trang tài liệu này . Ví dụ: char(10)sẽ bi quan dự trữ 40 byte dưới utf8mb4, nhưng varchar(10)sẽ phân bổ byte phù hợp với mã hóa độ dài thay đổi.
Kevin A. Naudé

1
@Kevin Tôi nghĩ bạn đã hiểu sai điều đó. Tôi nghĩ chiều dài hàng tối đa là 64k. Bạn chỉ có thể tạo một trường utf8mb4 bằng 1/4 vì nó phải dành lượng không gian đó. Vì vậy, ngay cả khi đó là ASCII, bạn chỉ có thể chèn 16k ký tự.
Tim Tisdall

1
@TimTisdall Ồ, bạn đang nói về giới hạn trên. Có, đó là thấp hơn. May mắn thay, các phiên bản hiện tại của mysql sẽ tự động nâng cấp từ varchar(n)lên textkiểu dữ liệu nếu bạn cố gắng thay đổi varchar(n)trường thành lớn hơn kích thước byte khả thi (trong khi đưa ra cảnh báo). Một chỉ mục cũng sẽ có giới hạn trên trong trường hợp xấu nhất thấp hơn và điều đó có thể gây ra các vấn đề khác.
Kevin A. Naudé

44

Để làm cho điều này 'vĩnh viễn', trong my.cnf:

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

Để kiểm tra, hãy chuyển đến máy khách và hiển thị một số biến:

SHOW VARIABLES LIKE 'character_set%';

Xác minh rằng tất cả chúng utf8, ngoại trừ ..._filesystem, điều phải binary..._dir, điểm nào đó trong cài đặt MySQL.


Nó không hoạt động trong trường hợp của tôi nhưng tôi vẫn tạo tệp my.cf trong / etc với nội dung nhất định. Tôi sử dụngcreate table my_name(field_name varchar(25) character set utf8);
Marek Bar

"HIỂN THỊ CÁC BIẾN TẦN THÍCH 'character_set%';" lệnh cho tôi biết vấn đề với kết nối của tôi. Cảm ơn!
javsmo

1
Điều này LAF không đúng. Những gì MySQL gọi utf8không phải là UTF-8 "đầy đủ".
TWR Cole

32

MySQL 4.1 trở lên có bộ ký tự mặc định mà nó gọi utf8nhưng thực chất chỉ là một tập con của UTF-8 (chỉ cho phép các ký tự 3 byte trở xuống).

Sử dụng utf8mb4làm bộ ký tự của bạn nếu bạn muốn UTF-8 "đầy đủ".


5
Chắc chắn đồng ý, đây là câu trả lời chính xác duy nhất. utf8không bao gồm các ký tự như biểu tượng cảm xúc. utf8mb4làm. Kiểm tra phần này để biết thêm thông tin về cách cập nhật: mathiasbynens.be/notes/mysql-utf8mb4
jibai31

@Basti - Hầu hết đúng (latin1 là mặc định cho đến gần đây) và chưa hoàn chỉnh (không thảo luận về việc chèn / chọn chính xác dữ liệu được mã hóa utf8, cũng như hiển thị trong html).
Rick James,

Trân trọng, @RickJames, Basti đã nói "cho đến nay" - Tôi không nhớ đã thấy câu trả lời của bạn khi tôi đăng bài này.
TWR Cole,

Than ôi, có khoảng 5 triệu chứng khác nhau rõ ràng của các vấn đề utf8 và khoảng 4 điều mà các lập trình viên làm sai dẫn đến rắc rối. Hầu hết các câu trả lời chỉ ra một điều có thể cần sửa chữa. Câu hỏi ban đầu là một câu hỏi rộng, vì vậy câu trả lời cần cả 4. Có lẽ Basti đã quen thuộc với một triệu chứng mà một khía cạnh của bạn là giải pháp.
Rick James,

8
Ngoài ra, tôi muốn dừng lại một chút và cho nhóm MySQL một cái nhìn chăm chỉ, thực sự tốt. o_o WTF các bạn đang nghĩ? Bạn có nhận ra rằng mình đã gieo rắc bao nhiêu sự nhầm lẫn khi tạo một đoạn mã trong chương trình của mình có tên "utf8" không thực sự là UTF-8 không? Đồ khốn kiếp. </rant>
TWR Cole

20

Câu trả lời ngắn gọn: Sử dụng utf8mb4ở 4 nơi:

  • Các byte trong ứng dụng khách của bạn là utf8, không phải latin1 / cp1251 / etc.
  • SET NAMES utf8mb4 hoặc thứ gì đó tương đương khi thiết lập kết nối của máy khách với MySQL
  • CHARACTER SET utf8mb4 trên tất cả các bảng / cột - ngoại trừ các cột hoàn toàn là ascii / hex / country_code / zip_code / etc.
  • <meta charset charset=UTF-8>nếu bạn đang xuất sang HTML. (Có, cách viết khác ở đây.)

Thông tin thêm ;
UTF8 tất cả các cách

Các liên kết trên cung cấp câu trả lời "cần có câu trả lời chính tắc chi tiết để giải quyết tất cả các mối quan tâm". - Có một giới hạn không gian trên diễn đàn này.

Biên tập

Ngoài việc CHARACTER SET utf8mb4chứa "tất cả" các ký tự trên thế giới, COLLATION utf8mb4_unicode_520_ciđược cho là đối chiếu 'tốt nhất trên toàn thế giới ' để sử dụng. (Ngoài ra còn có các câu ghép tiếng Thổ Nhĩ Kỳ, tiếng Tây Ban Nha, v.v., dành cho những ai muốn có sắc thái trong các ngôn ngữ đó.)


Liên kết mới của tôi về cách gỡ lỗi các sự cố utf8 từ đầu ra bạn nhận được.
Rick James

Tại sao unicode_520_ci không phải là tốt nhất: stackoverflow.com/a/49982378/62202
Louis

@Louis - Và như tôi ngụ ý người dùng Tây Ban Nha và Thổ Nhĩ Kỳ (cũng như Ba Lan) có thể không hài lòng. "Tốt nhất trên toàn thế giới" có xu hướng làm tổn thương một số người. MySQL 8.0 có một đối chiếu mới hơn "tốt nhất": utf8mb4_0900_ai_ci . Than ôi, một lần nữa L = Ł.
Rick James

4

Bộ ký tự là một thuộc tính của cơ sở dữ liệu (mặc định) và bảng. Bạn có thể xem (các lệnh 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

Nói cách khác; khá dễ dàng để kiểm tra bộ mã cơ sở dữ liệu của bạn hoặc thay đổi nó:

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

1
Điều này LAF không đúng. Những gì MySQL gọi utf8không phải là UTF-8 "đầy đủ".
TWR Cole


2

Tôi đã làm theo giải pháp của Javier, nhưng tôi đã thêm một số dòng khác nhau trong my.cnf:

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

Tôi tìm thấy ý tưởng này ở đây: http://dev.mysql.com/doc/refman/5.0/en/charset-server.html trong nhận xét đầu tiên / duy nhất của người dùng ở cuối trang. Anh ấy đề cập rằng bỏ qua-ký tự-thiết lập-khách hàng-bắt tay có một số tầm quan trọng.


Câu trả lời không được yêu thích, không có phiếu bầu này là điều duy nhất giúp tôi! Vì vậy, nó nhận được phiếu bầu của tôi, đó là điều chắc chắn. skip-character-set-client-handshakelà chìa khóa.
Marcus


0

Đặt của bạn database collationthành UTF-8 rồi áp dụng table collationcho cơ sở dữ liệu mặc định.


-1

Câu trả lời của bạn là bạn có thể cấu hình bằng MySql Settings. Trong Câu trả lời của tôi có thể là một cái gì đó đã biến mất khỏi ngữ cảnh nhưng điều này cũng biết là sự giúp đỡ cho bạn.
cách cấu hình Character SetCollation .

Đối với các ứng dụng lưu trữ dữ liệu bằng cách sử dụng bộ ký tự MySQL mặc định và collation ( latin1, latin1_swedish_ci), không cần cấu hình đặc biệt. Nếu các ứng dụng yêu cầu lưu trữ dữ liệu bằng cách sử dụng bộ ký tự hoặc đối chiếu khác, bạn có thể định cấu hình thông tin bộ ký tự theo một số cách:

  • Chỉ định cài đặt ký tự cho mỗi cơ sở dữ liệu. Ví dụ: các ứng dụng sử dụng một cơ sở dữ liệu có thể yêu cầu utf8, trong khi các ứng dụng sử dụng cơ sở dữ liệu khác có thể yêu cầu sjis.
  • Chỉ định cài đặt ký tự khi khởi động máy chủ. Điều này khiến máy chủ sử dụng các cài đặt đã cho cho tất cả các ứng dụng không thực hiện các sắp xếp khác.
  • Chỉ định cài đặt ký tự tại thời điểm cấu hình , nếu bạn xây dựng MySQL từ nguồn. Điều này khiến máy chủ sử dụng các cài đặt đã cho cho tất cả các ứng dụng mà không cần phải chỉ định chúng khi khởi động máy chủ.

Các ví dụ được hiển thị ở đây cho câu hỏi của bạn để đặt bộ ký tự utf8, tại đây cũng đặt đối chiếu để hữu ích hơn ( utf8_general_ciđối chiếu`).

Chỉ định cài đặt ký tự cho mỗi cơ sở dữ liệu

  CREATE DATABASE new_db
  DEFAULT CHARACTER SET utf8
  DEFAULT COLLATE utf8_general_ci;

Chỉ định cài đặt ký tự khi khởi động máy chủ

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

Chỉ định cài đặt ký tự tại thời điểm cấu hình MySQL

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

Để xem các giá trị của bộ ký tự và các biến hệ thống đối chiếu áp dụng cho kết nối của bạn, hãy sử dụng các câu lệnh sau:

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

Đây có thể là câu trả lời dài nhưng có tất cả các cách, bạn có thể sử dụng. Hy vọng câu trả lời của tôi là hữu ích cho bạn. để biết thêm thông tin http://dev.mysql.com/doc/refman/5.7/en/charset-application.html


-2

SET NAMES UTF8

Đây không phải là mẹo


2
Trong khi sử dụng SET NAMES UTF8(hoặc UTF8mb4) là đúng, bạn không giải thích nó làm gì (bộ ký tự được sử dụng cho kết nối này). "Đây không phải là mẹo" nghe có vẻ như nó sẽ giải quyết được vấn đề (làm cho MySQL xử lý UTF-8 đúng cách), nhưng nhiều cơ sở dữ liệu MySQL được đặt thành latin1 theo mặc định, vì vậy điều đó sẽ không làm cho nó trở thành một giải pháp thích hợp. Tôi sẽ thay đổi bộ ký tự mặc định và bảng mã thành utf8mb4. Thực sự, câu trả lời này không đầy đủ, vì vậy tôi đã từ chối nó.
cơ bản

-2

KẾT NỐI CƠ SỞ DỮ LIỆU VỚI 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

Đặt kết nối cơ sở dữ liệu của bạn thành UTF8:

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

Nếu đang chạy PHP, không sử dụng mysql_*giao diện không dùng nữa . Chuyển sang mysqli_*hoặc PDO.
Rick James

-3

Đã có thể tìm thấy một giải pháp. Xếp hạng sau như được chỉ định tại 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;

Hai dòng cuối cùng là thừa, vì dòng đầu tiên đã bao gồm những dòng: dev.mysql.com/doc/refman/5.0/en/charset-connection.html
DanielM

Cũng không phải là một giải pháp hoàn chỉnh. Các cột cầnCHARACTER SET utf8 . rootsẽ không thực hiện tất cả quan trọng init_connect.
Rick James
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.