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

BLOB có được chuyển đổi bằng cách sử dụng bộ ký tự hiện tại / mặc định trong MySQL không?

Câu trả lời ngắn gọn:

Chỉ cần xóa hoặc nhận xét dòng bên dưới và nó sẽ luôn hoạt động, bất kể mã hóa cơ sở dữ liệu nào đang thực sự được sử dụng (utf8 , latin1 , v.v.):

$pdo->exec('SET CHARACTER SET utf8');

Câu trả lời dài:

Đây không phải là lỗi PDO, đây là lỗi MySQL.

Khi mã hóa cơ sở dữ liệu thực tế là latin1 , nhưng bạn sử dụng:

SET CHARACTER SET utf8

(hoặc ngược lại:thực tế là utf8 , nhưng bạn sử dụng latin1 - phần quan trọng là nó khác nhau ), sau đó, theo như tôi có thể nói, MySQL sẽ cố gắng thực hiện chuyển đổi bộ ký tự cho tất cả lưu lượng truy cập giữa máy khách và máy chủ (ngay cả đối với BLOB !).

Nếu bạn KHÔNG sử dụng SET CHARACTER SET tuyên bố, từ những gì tôi thấy cho bộ mã kết nối tập lệnh (PHP / PDO hoặc Perl / DBI) theo mặc định được đặt thành bộ mã cơ sở dữ liệu và trong trường hợp đó, không có chuyển đổi ngầm nào diễn ra.

Rõ ràng, chuyển đổi tự động này là thứ giết chết BLOB, những thứ không muốn bất kỳ chuyển đổi nào xảy ra.

Tôi đã thử nghiệm điều này trên cả PHP / PDO và Perl / DBI, và vấn đề có thể dễ dàng tái tạo:cả hai sẽ không thành công nếu sử dụng cơ sở dữ liệu với latin1 mã hóa và sử dụng SET CHARACTER SET utf8 (hoặc ngược lại).

Nếu bạn muốn trở thành đầy đủ UTF8 tương thích, bạn nên thay đổi mã hóa cơ sở dữ liệu của mình bằng cách sử dụng:

ALTER DATABASE mydb CHARSET utf8;

Với điều này, mọi thứ sẽ sử dụng UTF8 và BLOB cũng sẽ hoạt động tốt.

Tệp tối thiểu gây ra sự cố hỏng này là blob.bin với byte đơn 0xFF . Trên Linux, bạn có thể tạo tệp thử nghiệm này bằng printf lệnh:

printf "0xFF" > blob.bin

Bây giờ, hãy kiểm tra các tập lệnh tái tạo sự cố:

Mã kiểm tra PHP:

<?php
$dbh = new PDO("mysql:host=127.0.0.1;dbname=test");
# If database encoding is NOT utf8, uncomment to break it:
# $dbh->exec("SET CHARACTER SET utf8");

$blob1 = file_get_contents("blob.bin");
$sth = $dbh->prepare(
    "INSERT INTO pdo_blob (the_blob) VALUES(:the_blob)"
);
$sth->bindParam(":the_blob", $blob1, PDO::PARAM_LOB);
$sth->execute();

$sth = $dbh->prepare(
    "SELECT the_blob FROM pdo_blob ORDER BY id DESC LIMIT 1"
);
$sth->execute();

$blob2 = null;
$sth->bindColumn(1, $blob2, PDO::PARAM_LOB);
$sth->fetch();

if ($blob1 == $blob2) {
    echo "Equal\n";
} else {
    echo "Not equal\n";
    $arr1 = str_split($blob1);
    $arr2 = str_split($blob2);
    $i=0;
    for ($i=0; $i<count($arr1); $i++) {
        if ($arr1[$i] != $arr2[$i]) {
            echo "First diff: " . dechex(ord($arr1[$i])) . " != "
                                . dechex(ord($arr2[$i])) . "\n";
            break;
        }
    }
}
?>

Mã kiểm tra Perl:

#!/usr/bin/perl -w

use strict;
use DBI qw(:sql_types);

my $dbh = DBI->connect("dbi:mysql:host=127.0.0.1;dbname=test");
# If database encoding is NOT utf8, uncomment to break it:
# $dbh->do("SET CHARACTER SET utf8");
open FILE, "blob.bin";
binmode FILE;
read(FILE, my $blob1, 100000000);
close FILE;
my $sth = $dbh->prepare(
    "INSERT INTO pdo_blob (the_blob) VALUES(?)"
);
$sth->bind_param(1, $blob1, SQL_BLOB);
$sth->execute();
my ($blob2) = $dbh->selectrow_array(
    "SELECT the_blob FROM pdo_blob ORDER BY id DESC LIMIT 1"
);
print ($blob1 eq $blob2 ? "Equal" : "Not equal") , "\n";


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Nhóm theo cột với sự phụ thuộc vào cột khác

  2. Làm cách nào để sử dụng mã hóa dữ liệu minh bạch với MySQL?

  3. Trường MySQL ORDER BY Date không có định dạng ngày tháng

  4. 193:% 1 không phải là lỗi ứng dụng Win32 hợp lệ với Ứng dụng Rails mới

  5. Chuyển đổi chuỗi DateTime trong Python thành số nguyên mili giây