Sẽ rất hữu ích nếu bạn hiểu các định nghĩa sau:
-
Một mã hóa ký tự nêu chi tiết cách từng biểu tượng được biểu diễn dưới dạng nhị phân (và do đó được lưu trữ trong máy tính). Ví dụ:ký hiệu
é
(U + 00E9, chữ cái Latinh nhỏ E với dấu sắc) là được mã hóa dưới dạng0xc3a9
trong UTF-8 (MySQL gọiutf8
) và0xe9
trong Windows-1252 (MySQL gọilatin1
). -
Một bộ ký tự là bảng chữ cái của các ký hiệu có thể được biểu diễn bằng cách sử dụng một bảng mã ký tự nhất định. Thật khó hiểu, thuật ngữ này cũng được sử dụng có nghĩa giống như mã hóa ký tự.
-
A đối chiếu là một thứ tự trên một tập ký tự, để các chuỗi có thể được so sánh. Ví dụ:
latin1_swedish_ci
của MySQL đối chiếu coi hầu hết các biến thể có dấu của một ký tự tương đương với ký tự cơ sở, trong khi của nólatin1_general_ci
đối chiếu sẽ sắp xếp thứ tự chúng trước ký tự cơ sở tiếp theo nhưng không tương đương (cũng có những khác biệt khác, quan trọng hơn,:chẳng hạn như thứ tự của các ký tự nhưå
,ä
,ö
vàß
).
MySQL sẽ quyết định đối chiếu nào nên được áp dụng cho một biểu thức nhất định như được ghi lại trong Đối chiếu các biểu thức :cụ thể là đối chiếu của một cột được ưu tiên hơn so với đối chiếu của một chuỗi ký tự.
WHERE
mệnh đề truy vấn của bạn so sánh các chuỗi sau:
-
một giá trị trong
fos_user.username
, được mã hóa trong bộ ký tự của cột (Windows-1252) và thể hiện tùy chọn đối chiếu của nólatin1_swedish_ci
(với giá trị cưỡng chế là 2); với -
chuỗi ký tự
'Nrv⧧Kasi'
, được mã hóa trong bộ ký tự của kết nối (UTF-8, như được định cấu hình bởi Doctrine) và thể hiện tùy chọn đối chiếu của kết nốiutf8_general_ci
(với giá trị cưỡng chế là 4).
Vì chuỗi đầu tiên trong số các chuỗi này có giá trị cưỡng chế thấp hơn chuỗi thứ hai, MySQL cố gắng thực hiện so sánh bằng cách sử dụng đối chiếu của chuỗi đó:latin1_swedish_ci
. Để làm như vậy, MySQL cố gắng chuyển đổi chuỗi thứ hai thành latin1
—Nhưng kể từ ⧧
ký tự không tồn tại trong bộ ký tự đó, so sánh không thành công.
Cảnh báo
Người ta nên tạm dừng một chút để xem xét cách cột hiện được mã hóa:bạn đang cố gắng lọc các bản ghi trong đó fos_user.username
bằng một chuỗi chứa ký tự không thể tồn tại trong cột đó !
Nếu bạn tin rằng cột không chứa các ký tự như vậy, thì bạn có thể đã ghi vào cột trong khi mã hóa ký tự kết nối được đặt thành thứ gì đó (ví dụ:latin1
) khiến MySQL diễn giải chuỗi byte đã nhận là các ký tự nằm trong bộ ký tự Windows-1252.
Nếu đúng như vậy, trước khi tiếp tục, bạn nên sửa dữ liệu của mình!
-
chuyển đổi các cột như vậy thành mã hóa ký tự đã được sử dụng khi chèn dữ liệu, nếu khác với mã hóa đương nhiệm:
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET foo;
-
thả thông tin mã hóa được liên kết với các cột như vậy bằng cách chuyển đổi chúng thành
binary
bộ ký tự:ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET binary;
-
kết hợp với các cột như vậy mã hóa mà dữ liệu đã thực sự được truyền bằng cách chuyển đổi chúng sang bộ ký tự có liên quan.
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET bar;
Lưu ý rằng, nếu chuyển đổi từ mã hóa nhiều byte, bạn có thể cần phải tăng kích thước của cột (hoặc thậm chí thay đổi loại của nó) để chứa độ dài tối đa có thể của chuỗi được chuyển đổi.
Một khi chắc chắn rằng các cột được mã hóa chính xác, người ta có thể buộc tiến hành so sánh bằng cách sử dụng đối chiếu Unicode bằng cách—
-
chuyển đổi rõ ràng giá trị
fos_user.username
thành một bộ ký tự Unicode:WHERE CONVERT(fos_user.username USING utf8) = ?
-
buộc chuỗi ký tự phải có giá trị cưỡng chế thấp hơn cột (sẽ gây ra chuyển đổi ngầm định giá trị của cột thành UTF-8):
WHERE fos_user.username = ? COLLATE utf8_general_ci
Hoặc một người có thể, như bạn nói, chuyển đổi vĩnh viễn (các) cột thành bảng mã Unicode và đặt đối chiếu của nó một cách thích hợp.
Nguyên tắc cân nhắc là các bảng mã Unicode chiếm nhiều không gian hơn các bộ ký tự byte đơn, vì vậy:
-
có thể cần thêm dung lượng;
-
so sánh có thể chậm hơn; và
-
Độ dài tiền tố chỉ mục có thể cần được điều chỉnh (lưu ý rằng độ dài tối đa tính bằng byte, do đó có thể thể hiện ít ký tự hơn trước đây).
Ngoài ra, hãy lưu ý rằng, như được ghi trong ALTER TABLE
Cú pháp
: