博客数据迁移

昨天想把以前的博客数据迁移回来,遇到了两个问题。

换域名

google一下

  1. 修改配置

    UPDATE wp_options SET option_value = replace(option_value, 'http://www.old-domain.com', 'http://www.new-domain.com')
    
  2. 修改博客文章的链接和文章内容中的链接

    UPDATE wp_posts SET guid = replace(guid, 'http://www.old-domain.com','http://www.new-domain.com');
    UPDATE wp_posts SET post_content = replace(post_content, 'http://www.old-domain.com', 'http://www.new-domain.com');
    

转乱码

旧博客数据是用mysqldump导出的一个sql文件,现在迁移数据就是直接把这个sql导入到新的数据库里面去。

  • 但是从wordpress直接访问的时候,所有的中文都是乱码。
  • 从命令行连接到数据库,用select命令选出博客内容,中文却能正常展示。

搜了一下,这个是比较常见的乱码问题。这篇博客里有相关的解释。

我旧的博客数据库,mysql server使用latin1的编码保存utf8编码的字节流,mysql server和博客的php程序通讯也使用的latin1的编码,
而博客最终在展示出页面的时候使用utf8编码输出文字,所以能正确的显示中文。
如果在wordpress中设置

define('DB_CHARSET', 'utf8');

mysql server和php通讯时使用utf8编码,就会出现乱码。

从命令行连接时,mysql client也是用latin1编码和mysql server通讯,而我的terminal则是使用utf8编码展示文字,所以也能正确的显示中文。
如果在命令行设置

set names utf8

mysql server和mysql client通讯时使用utf8编码,终端显示也就会出现乱码。

虽然旧的方式也能正常工作,但总归不是最正确的方法。我需要把新的数据库默认编码设置为utf8,保持一致。
解决的办法:

  • 先把备份的sql文件再次使用latin1编码导入数据库,再次用mysqldump导出数据,同时在参数中指明默认的编码

    mysql --default-character-set=latin1 -uroot oylbin_blog < old.sql
    mysqldump --default-character-set=latin1 -uroot oylbin_blog > new.sql
    
  • 打开new.sql,把开头注释中的

    /*!40101 SET NAMES latin1 */;
    

    修改为

    /*!40101 SET NAMES utf8 */;
    
  • 再将new.sql使用utf8编码导入数据库

    mysql --default-character-set=utf8 -uroot oylbin_blog < old.sql
    

现在的问题是解决了,但是,最根本的原因还是不是理解得很透彻,还是有些疑问:

  1. 在旧的数据库里面,为什么调用set names utf8之后,终端就会出乱码呢?
  2. 在mysql命令行中,可以用下面的命令查看编码相关的变量信息:

    SHOW VARIABLES LIKE 'character\_set\_%'
    

    这些参数的含义是什么,它们是怎样影响到整个编码处理的流程的呢?
    这个问题也找到一篇相关的博客文章,但是还没有细看,等有空的时候再仔细研究一下。

根据之前的解释,在default-character-set=latin1时,mysql client和mysql server通讯的时,server把client发送过来的query string都认为是latin1编码的。
我就在想,如果有下面这样一个insert语句

insert into table_name values(123,'中文字符串⋯⋯')

如果中文字符串里面,正巧有某个中文字符的utf8编码的某一个字节和单引号(0x27)相同,那么这个query string被server端解析的时候应该会出现语法错误吧。
于是我就看了一下utf8的编码规则,发现除了ascii的前127个字符,其他字符在utf编码时,所有的字节高位第一个bit都必然是1,所以不存在某个中文字符的字节中出现0x27的情况。于是我又看了一下GBKGB18030BIG5的编码规则,发现都是类似的情况,在一个字符需要多字节表示时,第一个字节高位必然是1,而后续字节中,一般都是从0x40开始编码,不会出现小于0x40的字节情况,这真是一件神奇的事情。为什么编码规则要设计成这样呢?而这种设计又正巧让mysql server可以在server端和client端编码实际上不一致的情况下正常工作⋯⋯

Comments