解决DataX支持Mysql 8的读写
前言:如果是第一次安装使用datax,或您服务器Mysql版本是 <= 5.7的,请先参考我之前的随笔:https://www.cnblogs.com/zifan/p/9194793.html。
背景:Mysql从5.6升级到8.0.19之后,发现原先正常跑的datax出错了。
先来看下我的报错信息:(看不清请放大网页)
1 2020-03-18 10:00:10.038 [0-0-0-writer] ERROR StdoutPluginCollector - 2 java.sql.SQLException: Could not retrieve transation read-only status server 3 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:996) ~[mysql-connector-java-5.1.34.jar:5.1.34] 4 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:935) ~[mysql-connector-java-5.1.34.jar:5.1.34] 5 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:924) ~[mysql-connector-java-5.1.34.jar:5.1.34] 6 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:870) ~[mysql-connector-java-5.1.34.jar:5.1.34] 7 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:902) ~[mysql-connector-java-5.1.34.jar:5.1.34] 8 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:892) ~[mysql-connector-java-5.1.34.jar:5.1.34] 9 at com.mysql.jdbc.ConnectionImpl.isReadOnly(ConnectionImpl.java:3607) ~[mysql-connector-java-5.1.34.jar:5.1.34] 10 at com.mysql.jdbc.ConnectionImpl.isReadOnly(ConnectionImpl.java:3576) ~[mysql-connector-java-5.1.34.jar:5.1.34] 11 at com.mysql.jdbc.PreparedStatement.checkReadOnlySafeStatement(PreparedStatement.java:1114) ~[mysql-connector-java-5.1.34.jar:5.1.34] 12 at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1134) ~[mysql-connector-java-5.1.34.jar:5.1.34] 13 at com.alibaba.datax.plugin.rdbms.writer.CommonRdbmsWriter$Task.doOneInsert(CommonRdbmsWriter.java:382) [plugin-rdbms-util-0.0.1-SNAPSHOT.jar:na] 14 at com.alibaba.datax.plugin.rdbms.writer.CommonRdbmsWriter$Task.doBatchInsert(CommonRdbmsWriter.java:362) [plugin-rdbms-util-0.0.1-SNAPSHOT.jar:na] 15 at com.alibaba.datax.plugin.rdbms.writer.CommonRdbmsWriter$Task.startWriteWithConnection(CommonRdbmsWriter.java:297) [plugin-rdbms-util-0.0.1-SNAPSHOT.jar:na] 16 at com.alibaba.datax.plugin.rdbms.writer.CommonRdbmsWriter$Task.startWrite(CommonRdbmsWriter.java:319) [plugin-rdbms-util-0.0.1-SNAPSHOT.jar:na] 17 at com.alibaba.datax.plugin.writer.mysqlwriter.MysqlWriter$Task.startWrite(MysqlWriter.java:78) [mysqlwriter-0.0.1-SNAPSHOT.jar:na] 18 at com.alibaba.datax.core.taskgroup.runner.WriterRunner.run(WriterRunner.java:56) [datax-core-0.0.1-SNAPSHOT.jar:na] 19 at java.lang.Thread.run(Thread.java:748) [na:1.8.0_241] 20 Caused by: java.sql.SQLException: Unknown system variable 'tx_read_only'
只需关注第一行和最后一行。第一行你去百度,部分资料会告诉你让你设置下数据库“事务隔离级别”,参考:https://www.cnblogs.com/jeffen/p/6005410.html
SET GLOBAL transaction_isolation='READ-COMMITTED';
本人也尝试过,对Mysql8而言报错依旧,不过其它mysql版本可以尝试该解决方案。参考:https://www.cnblogs.com/lewic/p/10685004.html,发现最终原因应该还是驱动版本的问题。
再来关注最后一行:java.sql.SQLException: Unknown system variable 'tx_read_only',大部分的资料表明是驱动版本不一致的问题。总结以上,致命原因只有一个,就是“mysql的驱动版本不对”,所以解决方案自然就是升级驱动了。
首先查看下原来的驱动:
ll {%Datax_Path}/plugin/writer/mysqlwriter/libs/ | grep mysql-con
截至2020/03/23,GitHub上下载的最新datax tar包 所包含的mysql驱动是mysql-connector-java-5.1.34.jar。的确不匹配啊,此时有人会第一时间想到从网上直接下载8的驱动丢进去或替换就好了,
参考:https://blog.csdn.net/jason_9527/article/details/100995505
思路没问题,不过不能彻底解决问题,而且会有一些error、warning出来。比如:
1、ERROR: zeroDateTimeBehavior=convertToNull要改为CONVERT_TO_NULL
2、WARN: Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary. 3、WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
所以我们要采用“修改源码,自行编译”的方式来彻底解决所有问题。参考:http://www.manongjc.com/detail/14-iexdburliccybhe.html
第一步下载源码:
git clone方式或直接https://github.com/alibaba/DataX/archive/master.zip下载。
第二步修改mysql-connector-java驱动的版本号:
找到位于 {DataX_source_code_home}/mysqlreader/ 和 {DataX_source_code_home}/mysqlwriter/ 下的pom.xml文件,将version的值改为8.0.X(可以直接搜索‘mysql-connector-java’快速定位,X写你自己想要的版本号)
如果你只用到了mysql的写,可以只修改mysqlwriter目录下的xml文件。
第三步修改zeroDateTimeBehavior的值convertToNull 为 CONVERT_TO_NULL:
编辑{DataX_source_code_home}/plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/util/DataBaseType.java
全文替换 convertToNull 为 CONVERT_TO_NULL
# 自行检索 {DataX_source_code_home}/文件夹下所有包含convertToNull字符串的文件,定位到文件再替换
vim {DataX_source_code_home}/plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/util/DataBaseType.java # 然后命令模式下全文替换 :%s/convertToNull/CONVERT_TO_NULL/
到此,如果跳过第四、五步直接打包datax,程序已经能正确运行,如果想完美解决其他警告,请按步骤继续。
第四步修改jdbc驱动的名称com.mysql.jdbc.Driver 为 com.mysql.cj.jdbc.Driver
vi {DataX_source_code_home}/plugin-rdbms-util/src/main/java/com/alibaba/datax/plugin/rdbms/util/DataBaseType.java vi {DataX_source_code_home}/adswriter/src/main/java/com/alibaba/datax/plugin/writer/adswriter/load/AdsHelper.java
全文替换 com.mysql.jdbc.Driver 为 com.mysql.cj.jdbc.Driver。
第五步jdbc链接追加useSSL=false设置:
比如:python datax.py file.json , 则file.json的配置项:"jdbcUrl":"jdbc:mysql://${writer_gateway}/oms?useUnicode=true&characterEncoding=UTF-8&useSSL=false",
第六步通过maven打包:(本人是参考Git上开发者提供的操作步骤来的)
cd {DataX_source_code_home} mvn -U clean package assembly:assembly -Dmaven.test.skip=true
打包成功,日志显示如下:
[INFO] BUILD SUCCESS
[INFO] -----------------------------------------------------------------
[INFO] Total time: 08:12 min
[INFO] Finished at: 2015-12-13T16:26:48+08:00
[INFO] Final Memory: 133M/960M
[INFO] -----------------------------------------------------------------
打包成功后的DataX包位于 {DataX_source_code_home}/target/datax/datax/ ,查看datax/plugin/writer/mysqlwriter/libs/目录,已经包含新版的驱动jar包
最后一步:
就是把datax移动到你希望的位置,然后执行:python datax.py ./file.json,至此,OVER