如何在单个Java项目中同时对接MySQL 5与MySQL 8数据库?
解决MySQL 5与MySQL 8双向数据同步的JDBC依赖冲突问题
核心问题定位
MySQL Connector/J的版本兼容性限制导致单项目内同时连接两个版本数据库时出现依赖冲突:8.x版本驱动不兼容MySQL 5,5.x版本驱动无法适配MySQL 8;多模块方案中类加载的优先级会导致低版本驱动被高版本覆盖,手动指定驱动类也无法解决类加载冲突问题。
可行解决方案
1. 类加载器隔离(单项目最可靠方案)
通过自定义独立类加载器分别加载两个版本的驱动包,避免类加载冲突:
- 将
mysql-connector-java-5.1.49.jar和mysql-connector-java-8.4.0.jar放到项目独立目录(如lib/mysql5、lib/mysql8),不要加入Maven/Gradle的依赖管理。 - 自定义类加载器加载对应驱动:
// MySQL5专用类加载器 URLClassLoader mysql5ClassLoader = new URLClassLoader( new URL[]{new File("lib/mysql5/mysql-connector-java-5.1.49.jar").toURI().toURL()}, null // 不继承系统类加载器,彻底隔离 ); // MySQL8专用类加载器 URLClassLoader mysql8ClassLoader = new URLClassLoader( new URL[]{new File("lib/mysql8/mysql-connector-java-8.4.0.jar").toURI().toURL()}, null ); - 加载驱动并建立连接:
// 建立MySQL5连接 Class<?> mysql5DriverClass = mysql5ClassLoader.loadClass("com.mysql.jdbc.Driver"); Driver mysql5Driver = (Driver) mysql5DriverClass.getDeclaredConstructor().newInstance(); Properties mysql5Props = new Properties(); mysql5Props.setProperty("user", "root"); mysql5Props.setProperty("password", "your_pwd"); Connection mysql5Conn = mysql5Driver.connect("jdbc:mysql://old-db:3306/db_name?useSSL=false&characterEncoding=utf8", mysql5Props); // 建立MySQL8连接 Class<?> mysql8DriverClass = mysql8ClassLoader.loadClass("com.mysql.cj.jdbc.Driver"); Driver mysql8Driver = (Driver) mysql8DriverClass.getDeclaredConstructor().newInstance(); Properties mysql8Props = new Properties(); mysql8Props.setProperty("user", "root"); mysql8Props.setProperty("password", "your_pwd"); Connection mysql8Conn = mysql8Driver.connect("jdbc:mysql://new-db:3306/db_name?useSSL=false&serverTimezone=UTC", mysql8Props); - 注意:将旧库、新库的操作逻辑分别封装到独立类中,用对应类加载器加载这些逻辑类,避免类型转换异常。
2. 规范多模块依赖关系
如果坚持使用多模块,需严格控制依赖方向:
- 模块X(负责MySQL5操作):仅依赖
mysql-connector-java:5.1.49,不依赖任何使用高版本驱动的模块 - 模块Y(负责MySQL8操作):仅依赖
mysql-connector-java:8.4.0 - 主模块Z:同时依赖X和Y,自身不直接依赖任何MySQL驱动
这种结构能保证模块X、Y的类加载器各自使用对应版本的驱动,不会互相覆盖。
3. 双向同步逻辑要点
- 避免循环同步:给同步数据添加
sync_flag字段标记来源(旧库/新库),同步时跳过已同步数据;或用时间戳对比,仅同步上次同步后新增/修改的数据。 - 定时同步实现:用
ScheduledExecutorService执行定时任务:ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); // 每小时执行一次同步 scheduler.scheduleAtFixedRate(() -> { syncOldToNew(); // 旧库指定表同步到新库 syncNewToOld(); // 新库指定表同步到旧库 }, 0, 1, TimeUnit.HOURS); - 性能优化:使用JDBC批量操作(
addBatch()、executeBatch())提升同步效率。
避坑提示
- 禁止在同一个类加载器下同时加载两个版本的MySQL驱动,类全限定名冲突会导致加载混乱。
- MySQL5的JDBC URL不要加
serverTimezone参数(5.x驱动不支持);MySQL8的URL必须指定该参数,否则会报错。
内容的提问来源于stack exchange,提问作者nathlrowe
相关产品推荐
相关产品推荐

