Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Dữ liệu utf8 trông ổn trong mysql nhưng bị hỏng trong đường ray

Khi máy khách MySQL tương tác với máy chủ:

  1. máy chủ nhận bất kỳ văn bản nào chỉ đơn thuần là một chuỗi byte; trước đó khách hàng sẽ cho nó biết cách mã hóa văn bản như vậy.

  2. nếu sau đó máy chủ phải lưu trữ văn bản đó trong một bảng, thì nó phải chuyển mã nó sang mã hóa của cột có liên quan (nếu khác).

  3. nếu sau đó máy khách muốn truy xuất văn bản như vậy, máy chủ phải chuyển mã nó sang mã hóa mà máy khách mong đợi.

Nếu các mã hóa được khách hàng sử dụng ở bước 1 và 3 là giống nhau (điều này thường xảy ra, đặc biệt là khi ứng dụng khách trong cả hai trường hợp là cùng một ứng dụng), sau đó thường không được chú ý nếu khách hàng đang sử dụng một mã hóa khác với mã hóa mà nó đã nói. Ví dụ:giả sử máy khách nói với MySQL rằng nó sẽ sử dụng latin1 , nhưng thực sự gửi dữ liệu trong utf8 :

  • Chuỗi 'Jazz–Man' được gửi đến máy chủ trong UTF-8 dưới dạng 0x4a617a7ae280934d616e .

  • MySQL, giải mã các byte đó trong Windows-1252, hiểu chúng để đại diện cho chuỗi 'Jazz–Man' .

  • Để lưu trữ trong utf8 cột, MySQL chuyển mã chuỗi sang mã hóa UTF-8 của nó 0x4a617a7ac3a2e282ace2809c4d616e . Điều này có thể được xác minh bằng cách sử dụng SELECT HEX(name) FROM lessons WHERE id=79510 .

  • Khi máy khách truy xuất giá trị, MySQL nghĩ rằng nó muốn nó trong latin1 và do đó chuyển mã sang mã hóa Windows-1252 0x4a617a7ae280934d616e .

  • Khi máy khách nhận được các byte đó, nó sẽ giải mã chúng thành UTF-8 và do đó hiểu chuỗi là 'Jazz–Man' .

Kết luận :khách hàng không nhận ra bất cứ điều gì là sai. Sự cố chỉ được phát hiện khi một ứng dụng khách khác (ứng dụng không ghi sai kết nối UTF-8 của nó là latin1 ) cố gắng sử dụng bảng. Trong trường hợp của bạn, điều này xảy ra khi mysqldump lấy được dữ liệu xuất; sử dụng --default-character-set=latin1 --skip-set-charset các tùy chọn đã buộc mysqldump hoạt động theo cách bị hỏng giống như ứng dụng của bạn một cách hiệu quả, do đó, nó kết thúc với dữ liệu được mã hóa chính xác.

Để khắc phục sự cố của bạn trong tương lai, bạn phải:

  1. Định cấu hình ứng dụng của bạn để ứng dụng đặt chính xác bộ ký tự kết nối MySQL (ví dụ:đặt encoding: utf8 trong config/database.yml cho Rails);

  2. Mã hóa dữ liệu trong cơ sở dữ liệu của bạn, ví dụ:UPDATE lessons SET name = BINARY CONVERT(name USING latin1) (lưu ý rằng điều này phải được thực hiện cho mọi cột văn bản được mã hóa sai).

Cũng lưu ý rằng bạn có thể sẽ muốn thực hiện hai hành động này một cách nguyên tử, điều này có thể cần một chút suy nghĩ.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Hỗ trợ MySQL cho Python không theo Giấy phép giống GPL

  2. Có thể có đối chiếu utf8 phân biệt trọng âm và không phân biệt chữ hoa chữ thường trong mysql không?

  3. Gọi thủ tục được lưu trữ bằng ADODB trong PHP

  4. MySql:Đếm số lần các từ xuất hiện trong một cột

  5. Kỹ thuật tốt nhất để lưu vào bộ nhớ đệm kết quả từ các truy vấn không thường xuyên thay đổi