下面我们来复现下:
5.5的表现
5.6的表现
很明显5.6的报错信息更精确些,5.5的报错太不人性化了,容易造成误解。
它们差别在于5.6的报错处理在语义分析阶段,精准的定位了错误信息。
而5.5的报错处理在执行阶段。
我们先来看看5.5的执行流程:
<code>dict_load_foreigns</code>:这个函数由于承担的责任太多,只要发现错误,就笼统的抛出<code>error on rename of 'xxxx' to 'xxxx' (errno: xxx)</code>的错误.
bug中这个ddl虽然执行失败了,但实际上foreign key reply_ibfk_2被删除了。这个bug在单机环境下影响不大,但在主备环境下由于ddl执行失败并没有记binlog,从而导致主备表结构不一致。这个bug只出现在5.6以前的版本中,5.6是ok的
我们来看看5.5的流程:
出错回滚之前的修改,预期是回滚删除外键reply_ibfk_2,但是删除外键reply_ibfk_2操作在第一次<code>mysql_rename_table</code>中,属于一个事务,而回滚操作在第二次<code>mysql_rename_table</code>中,属于另一个事务,因此回滚没有成功。
那么5.6为什么没有出现这种错误呢?5.6在语义分析的时候就发现错误,还没来得及删外键就已经报错返回了。
5.5修复方法,将删外键的操作放到第二次<code>mysql_rename_table</code>中进行,如果出现错误就可以顺利的回滚了。当然,还是5.6的做法比较好。