mysql 8.0+ 与 datax 的 mysqlreader/mysqlwriter 默认不兼容,需替换为 mysql-connector-java-8.0.33.jar 驱动、在 jdbcurl 中指定 caching_sha2_password 插件,并手动处理 json/datetime(6)/生成列、主键冲突、缺失 update_time 及 strict_trans_tables 模式等问题。

mysqlreader 和 mysqlwriter 能直接跑通新版 MySQL(8.0+),但默认配置会失败——关键卡在驱动兼容性和认证插件上。
连接失败:Authentication plugin 'caching_sha2_password' cannot be loaded
这是新版 MySQL 默认认证方式,而 DataX 自带的 mysql-connector-java-5.1.37.jar 不支持。不换驱动,连都连不上。
- 下载
mysql-connector-java-8.0.33.jar(必须 8.0.x,5.1.x 或 8.1+ 都有兼容问题) - 替换
datax/plugin/reader/mysqlreader/libs/和datax/plugin/writer/mysqlwriter/libs/下的旧 jar - 在
jdbcUrl中显式指定认证插件:jdbc:mysql://host:3306/db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false&authenticationPlugins=caching_sha2_password
字段类型不兼容:json、datetime(6)、generated column 同步报错
DataX 3.0 对 MySQL 8 新类型支持有限,mysqlreader 读取 JSON 字段会抛 SQLException: Cannot convert class java.lang.String to class java.lang.Object;datetime(6) 可能被截断为秒级。
- 对含
JSON字段的表,改用querySql显式转成字符串:"querySql":["SELECT id, name, CAST(profile AS CHAR) AS profile FROM users"] - 避免
column: ["*"],手动列出字段并过滤掉生成列(GENERATED ALWAYS AS)、不可读列 -
datetime字段若精度为(6),目标库需同样定义为datetime(6),且mysqlwriter的writeMode不能设为replace(会触发隐式类型转换)
全量同步时主键冲突或自增 ID 错乱
老旧实例用 MyISAM 或低版本 InnoDB,自增逻辑与新版不一致;若目标表已存在数据,insert 模式直接报 Duplicate entry。
- 优先用
preSql清空或重置目标表:"preSql": ["TRUNCATE TABLE users", "ALTER TABLE users AUTO_INCREMENT = 1"] - 禁用目标表自增约束临时写入:
"postSql": ["ALTER TABLE users AUTO_INCREMENT = (SELECT MAX(id)+1 FROM users)"] - 如需保留源 ID,确保目标表
id字段无ON UPDATE CURRENT_TIMESTAMP等干扰逻辑
增量同步依赖时间字段,但老库没 update_time
很多老旧表只有 create_time,无法做“按更新时间增量”。硬加 where 条件会漏数据,用 splitPk 分片又可能重复拉取。
- 方案一:给老表加
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(需 DBA 授权 ALTER) - 方案二:用
querySql+ 子查询模拟增量,例如:"querySql":["SELECT * FROM orders WHERE id > (SELECT COALESCE(MAX(id), 0) FROM target_orders)"] - 方案三:借助
binlog(需开启)+canal或maxwell,DataX 不适合做实时增量
真正容易被忽略的是:新版 MySQL 的 sql_mode 默认包含 STRICT_TRANS_TABLES,而老库往往宽松。DataX 写入时若遇到空字符串插入 NOT NULL 字段,会直接失败,不是警告。务必检查目标库 sql_mode,或在 preSql 中临时 set:"preSql": ["SET SESSION sql_mode = 'NO_ENGINE_SUBSTITUTION'"]。











