我在 MySQL 5.6 中有一些表,在某些字段中包含大量二进制数据。我想知道我是否可以信任由创建的转储,mysqldump
并确保在通过 FTP、SCP 等系统传输转储文件时不会轻易损坏这些二进制字段。另外,我是否应该强制此类系统将转储文件视为二进制传输而不是 ascii?
提前感谢您的任何评论!
我在 MySQL 5.6 中有一些表,在某些字段中包含大量二进制数据。我想知道我是否可以信任由创建的转储,mysqldump
并确保在通过 FTP、SCP 等系统传输转储文件时不会轻易损坏这些二进制字段。另外,我是否应该强制此类系统将转储文件视为二进制传输而不是 ascii?
提前感谢您的任何评论!
不,当您有二进制 blob 时,它并不总是可靠的。在这种情况下,您必须使用“ --hex-blob ”标志来获得正确的结果。
来自以下评论的警告:
如果将 --hex-blob 与 -T 标志(每个表的文件)结合使用,则 hex-blob 标志将被忽略,静默
我有一个案例,这些调用失败(在不同的服务器上导入,但都运行 Centos6/MariaDB 10):
mysqldump --single-transaction --routines --databases myalarm -uroot -p"PASSWORD" | gzip > /FILENAME.sql.gz
gunzip < FILENAME.sql.gz | mysql -p"PASSWORD" -uroot --comments
它会生成一个静默无法导入的文件。添加“--skip-extended-insert”给了我一个更容易调试的文件,我发现该行已生成但无法读取(但导出或导入均未报告错误):
INSERT INTO `panels` VALUES (1003,1,257126,141,6562,1,88891,'??\\\?ŖeV???,NULL);
请注意,原始数据中缺少二进制数据的终止引号。
select hex(packet_key) from panels where id=1003;
--> DE77CF5C075CE002C596176556AAF9ED
该列是二进制数据:
CREATE TABLE `panels` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`enabled` tinyint(1) NOT NULL DEFAULT '1',
`serial_number` int(10) unsigned NOT NULL,
`panel_types_id` int(11) NOT NULL,
`all_panels_id` int(11) NOT NULL,
`installers_id` int(11) DEFAULT NULL,
`users_id` int(11) DEFAULT NULL,
`packet_key` binary(16) NOT NULL,
`user_deleted` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
...
所以不,你不仅可以不一定信任mysqldump,甚至不能依赖它在发生错误时报告错误。
我使用的一个丑陋的解决方法是通过在转储中添加这样的选项来排除两个受影响的表:
--ignore-table=myalarm.panels
然后这个 BASH 脚本破解。基本上运行一个 SELECT 来生成 INSERT 值,其中处理 NULL 列并且二进制列变成一个 UNHEX() 调用,如下所示:
(123,45678,UNHEX("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),"2014-03-17 00:00:00",NULL),
如果需要,将其粘贴到您选择的编辑器中以使用它。
echo "SET UNIQUE_CHECKS=0;SET FOREIGN_KEY_CHECKS=0;DELETE FROM panels;INSERT INTO panels VALUES " > all.sql
mysql -uroot -p"PASSWORD" databasename -e "SELECT CONCAT('(',id,',', enabled,',', serial_number,',', panel_types_id,',', all_panels_id,',', IFNULL(CONVERT(installers_id,CHAR(20)),'NULL'),',', IFNULL(CONVERT(users_id,CHAR(20)),'NULL'), ',UNHEX(\"',HEX(packet_key),'\"),', IF(ISNULL(user_deleted),'NULL',CONCAT('\"', user_deleted,'\"')),'),') FROM panels" >> all.sql
echo "SET UNIQUE_CHECKS=1;SET FOREIGN_KEY_CHECKS=1;" > all.sql
这给了我一个名为“all.sql”的文件,它需要将 INSERT 中的最后一个逗号变成分号,然后它可以像上面一样运行。我需要在交互式 mysql shell 和命令行中设置“大型导入缓冲区”调整来处理该文件,因为它很大。
mysql ... --max_allowed_packet=1GB
当我报告这个错误时,我最终被指向了“--hex-blob”标志,它与我的解决方法相同,但从我的角度来看是微不足道的。添加该选项,blob 被转储为十六进制,结束。
生成的转储是mysqldump
可以信任的。
为避免编码、二进制传输等问题,请使用该--hex-blob
选项,以便将每个字节转换为十六进制数(例如,'abc' 变为 0x616263)。它会使转储变得更大,但它将是获取信息的最兼容和最安全的方式(因为它将是纯文本,不会由于文本文件中的二进制数据生成的特殊符号而导致奇怪的误解)。
您可以确保将转储文件打包成 rar 或 zip 文件的完整性(并加快传输速度)。这样,您可以轻松检测到它没有因传输而损坏。
当您尝试将其加载到服务器上时,请检查您是否已在my.cnf
服务器配置文件中分配
[mysqld]
max_allowed_packet=600M
或更多,如果需要。
顺便说一句,现在我刚刚进行了迁移,并转储了许多二进制数据,mysqldump
并且效果很好。
是的,您可以信任由mysqldump
.
是的,您应该使用二进制传输以避免传输过程中的任何编码转换。MySQL 转储向转储添加控制命令,以便服务器在重新导入时以特定编码解释文件。您不想更改此编码。