(目录)
问题
使用binlog2sql解析MySQL8.0时发现列与值的对应关系错误,无法直接使用解析出的语句进行回滚
原因
SELECT FROM COLUMNS表不会自动排序, 安装binlog2sql时使用的pymysqlreplication依赖包版本较低,其中也没有对列进行排序。 参考: MySQL :: MySQL 8.0 Reference Manual :: 26.3.8 The INFORMATION_SCHEMA COLUMNS Table
处理方法
更改pymysqlreplication/binlogstream.py
中的代码。在__get_table_information
中添加上order by ORDINAL_POSITION asc
更改后的记录
def __get_table_information(self, schema, table):
for i in range(1, 3):
try:
if not self.__connected_ctl:
self.__connect_to_ctl()
cur = self._ctl_connection.cursor()
cur.execute(
"""
SELECT
COLUMN_NAME, COLLATION_NAME, CHARACTER_SET_NAME,
COLUMN_COMMENT, COLUMN_TYPE, COLUMN_KEY
FROM
information_schema.columns
WHERE
table_schema = %s AND table_name = %s
ORDER BY ORDINAL_POSITION ASC
""", (schema, table))
return cur.fetchall()
except pymysql.OperationalError as error:
code, message = error.args
if code in MYSQL_EXPECTED_ERROR_CODES:
self.__connected_ctl = False
continue
else:
raise error
排查过程
检查数据库信息
首先列与值的对应关系错误,但是列名和值都是没问题的,怀疑是从information_schema.columns从获取列信息时出现问题,然后查询information_schema.columns表,发现查询出现问题的表时,结果中的ORDINAL_POSITION不是升序排列的,没有问题的表结果是按照ORDINAL_POSITION升序排列的,进而怀疑是在获取列信息时没有进行排序。
检查源码
首先检查binlog2sql的代码,发现没有对information_schema.columns中的查询,估计是从import中进行的调用,查看解析SQL的执行过程 binlog2sql.py文件中binlog2sql.process_binlog() 中调用BinLogStreamReader from pymysqlreplication import BinLogStreamReader 继续排查pymysqlreplication中的内容 当前安装的pymysqlreplication版本0.13,查看对应源码 BinLogStreamReader在binlogstream.py文件中,其中有一个函数__get_table_information(self, schema, table)确认是获取列信息时没有排序 内容是从information_schema.columns中获取列信息,源记录:
def __get_table_information(self, schema, table):
for i in range(1, 3):
try:
if not self.__connected_ctl:
self.__connect_to_ctl()
cur = self._ctl_connection.cursor()
cur.execute(
"""
SELECT
COLUMN_NAME, COLLATION_NAME, CHARACTER_SET_NAME,
COLUMN_COMMENT, COLUMN_TYPE, COLUMN_KEY
FROM
information_schema.columns
WHERE
table_schema = %s AND table_name = %s
""", (schema, table))
return cur.fetchall()
except pymysql.OperationalError as error:
code, message = error.args
if code in MYSQL_EXPECTED_ERROR_CODES:
self.__connected_ctl = False
continue
else:
raise error