惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
爱范儿
爱范儿
H
Help Net Security
V
Visual Studio Blog
J
Java Code Geeks
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
MyScale Blog
MyScale Blog
The Cloudflare Blog
Martin Fowler
Martin Fowler
D
Docker
腾讯CDC
F
Fortinet All Blogs
雷峰网
雷峰网
GbyAI
GbyAI
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Blog — PlanetScale
Blog — PlanetScale
Engineering at Meta
Engineering at Meta
博客园 - 聂微东
博客园 - 叶小钗

博客园 - 青石路

好好的OceanBase官方驱动你不用,非要用第三方驱动,ArrayIndexOutOfBoundsException了吧 记一次Qoder排查mave-shade-plugin只重定向部分package导致的NoSuchMethodError问题,查的还挺快的 如果写Redis序列化与读Redis序列化不一致,你觉得会发生什么 记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来 Claude Code安装,接入阿里云百炼模型,蹭蹭免费额度 异源数据同步 → 记一次 DataX 已同步数据量优化 明明连接的是Redis的DB0,为什么能查到DB3的数据? TINYINT(1) 类型的字段,明明数据存的是 2,为什么查出来是 true 用了MySQL的INSERT ON DUPLICATE KEY UPDATE,怎么还报唯一索引冲突错误 那些年不该放到事务中的操作,你实现过哪些 关于布尔类型的变量不要加 is 前缀,被网友们吐槽了,特来完善下 都说了布尔类型的变量不要加 is 前缀,非要加,这不是坑我了嘛 安全漏洞修复导致SpringBoot2.7与Springfox不兼容,问题排查与处理 记一次SQL隐式转换导致精度丢失问题的排查 → 不规范就踩坑 经由同个文件多次压缩的文件MD5都不一样问题排查,感慨AI的强大! 记一次cannot access its superinterface问题的的排查 → 强如Spring也一样写Bug SpringBoot支持Kafka多源配置的同时还要支持启停配置化,是真的会玩 如果XXL-JOB执行器在执行某任务中被重启了,重启后该任务能够被自动弥补调度吗 Spring Boot读取外部配置文件失败,原因绝对出乎你意料 不依赖 Spring,你会如何自实现 RabbitMQ 消息的消费(一) 异源数据同步 → DataX 同步启动后如何手动终止? 异源数据同步 → 如何获取 DataX 已同步数据量? 记一次 RabbitMQ 消费者莫名消失问题的排查 不升级 POI 版本,如何生成符合新版标准的Excel 2007文件 maven 插件之 maven-shade-plugin,解决同包同名 class 共存问题的神器
以MySQL为例,来看看maven-shade-plugin如何解决多版本驱动共...
青石路 · 2024-09-02 · via 博客园 - 青石路

开心一刻

清明节那天,看到一小孩在路边烧纸
时不时地偷偷往火堆里扔几张考试卷子
边烧边念叨:爷爷呀,你岁数大了,在那边多做做题吧,对脑子好,要是有不懂的地方,就把我老师带走,让他教您!

开心一刻

前提说明

假设 MySQL 5.7.36 的库 qsl_datax

mysql5

有表 qsl_datax_source 和 数据

CREATE TABLE `qsl_datax_source`  (
  `id` bigint(20) NOT NULL COMMENT '自增主键',
  `username` varchar(255) NOT NULL COMMENT '姓名',
  `password` varchar(255) NOT NULL COMMENT '密码',
  `birth_day` date NOT NULL COMMENT '出生日期',
  `remark` text,
  PRIMARY KEY (`id`)
) ENGINE = InnoDB ;
INSERT INTO `qsl_datax_source` VALUES (1, '张三', 'z123456', '1991-01-01', '张三');
INSERT INTO `qsl_datax_source` VALUES (2, '李四', 'l123456', '1992-01-01', '李四');
INSERT INTO `qsl_datax_source` VALUES (3, '王五', 'w123456', '1993-01-01', '王五');
INSERT INTO `qsl_datax_source` VALUES (4, '麻子', 'm123456', '1994-01-01', '麻子');

需要将表中数据同步到 MySQL 8.0.30

mysql8

sql_db 库的 qsl_datax_source 表中,并且只用 JDBC 的方式,该如何实现?你们可能觉得非常简单,直接引入 mysql-connector-j 依赖

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.0.33</version>
</dependency>

然后直接写同步代码

public static void main(String[] args) throws Exception {
    String url5 = "jdbc:mysql://192.168.2.118:3307/qsl_datax?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
    String url8 = "jdbc:mysql://192.168.2.118:3311/sql_db?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
    Properties pro = new Properties();
    pro.put("user", "root");
    pro.put("password", "123456");
    // 加载驱动类
    Class.forName("com.mysql.cj.jdbc.Driver");
    // 建立连接
    Connection conn5 = DriverManager.getConnection(url5, pro);
    // 查数据
    Statement statement = conn5.createStatement();
    ResultSet resultSet = statement.executeQuery("SELECT * FROM qsl_datax_source");
    StringBuilder insertSql = new StringBuilder("INSERT INTO qsl_datax_source(id,username,password,birth_day,remark) VALUES ");
    while (resultSet.next()) {
        // 拼接sql
        insertSql.append("(")
                .append(resultSet.getLong("id")).append(",")
                .append("'").append(resultSet.getString("username")).append("',")
                .append("'").append(resultSet.getString("password")).append("',")
                .append("'").append(resultSet.getString("birth_day")).append("',")
                .append("'").append(resultSet.getString("remark")).append("'")
                .append("),");
    }
    // 因为mysql5和mysql8的账密是一样的,所以用的同一个 pro
    Connection conn8 = DriverManager.getConnection(url8, pro);
    Statement stmt = conn8.createStatement();
    int count = stmt.executeUpdate(insertSql.substring(0, insertSql.length() - 1));
    System.out.println("新插入记录数:" + count);

    resultSet.close();
    statement.close();
    stmt.close();
    conn5.close();
    conn8.close();
}

执行后输出

新插入记录数:4

MySQL 8.0.30 的库 sql_db 查看表 qsl_datax_source 的数据

同驱动同步成功

同步完成,这不是有手就行吗?

行不行

一般来说,高版本的驱动会兼容低版本的数据库,但也不绝对,或者说兼容不全;MySQL版本、驱动版本、JDK版本对应关系如下

mysql版本驱动版本jdk版本对应关系

mysql-connector-j 8.0.33 驱动兼容 MySQL 5.7.36,所以上面的同步没问题,但如果 MySQL 版本很低(比如:5.1.x),例如从 MySQL 5.1.8 同步到 MySQL 8.0.30 ,如上同步代码还能同步成功吗(我就不去试了,你们也别去试了,因为引申目的已经达到了),所以保险做法是

mysql-connector-j 8.0.33 操作 MySQL 8.0.30

mysql-connector-java 5.1.49 操作 MySQL 5.7.36

mysql-connector-java 5.0.x 操作 MySQL 5.0.x

所以问题就来了

如何用 mysql-connector-java 5.1.49 从 MySQL 5.7.36 查数据后,用 mysql-connector-j 8.0.33 将数据插入 MySQL 8.0.30

多驱动操作

你们肯定也觉得简单,继续引入 mysql-connector-java 5.1.49 依赖

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.0.33</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

然后调整代码

public static void main(String[] args) throws Exception {
    String url5 = "jdbc:mysql://192.168.2.118:3307/qsl_datax?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
    String url8 = "jdbc:mysql://192.168.2.118:3311/sql_db?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
    Properties pro = new Properties();
    pro.put("user", "root");
    pro.put("password", "123456");
    // 加载驱动类
    Class.forName("com.mysql.jdbc.Driver");
    // 建立连接
    Connection conn5 = DriverManager.getConnection(url5, pro);
    // 查数据
    Statement statement = conn5.createStatement();
    ResultSet resultSet = statement.executeQuery("SELECT * FROM qsl_datax_source");
    StringBuilder insertSql = new StringBuilder("INSERT INTO qsl_datax_source(id,username,password,birth_day,remark) VALUES ");
    while (resultSet.next()) {
        // 拼接sql
        insertSql.append("(")
                .append(resultSet.getLong("id")).append(",")
                .append("'").append(resultSet.getString("username")).append("',")
                .append("'").append(resultSet.getString("password")).append("',")
                .append("'").append(resultSet.getString("birth_day")).append("',")
                .append("'").append(resultSet.getString("remark")).append("'")
                .append("),");
    }
    Class.forName("com.mysql.cj.jdbc.Driver");
    // 因为mysql5和mysql8的账密是一样的,所以用的同一个 pro
    Connection conn8 = DriverManager.getConnection(url8, pro);
    Statement stmt = conn8.createStatement();
    int count = stmt.executeUpdate(insertSql.substring(0, insertSql.length() - 1));
    System.out.println("新插入记录数:" + count);

    resultSet.close();
    statement.close();
    stmt.close();
    conn5.close();
    conn8.close();
}

和之前代码对比下

多驱动使用前后代码比较

调整甚微;执行后输出结果如下

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.
新插入记录数:4

如果只从结果来看,确实同步成功了,但第一行的 警告 值得得我们琢磨下

类 com.mysql.jdbc.Driver 加载中。这个类已经被弃用。新的驱动类是 com.mysql.cj.jdbc.Driver,这个驱动通过 SPI 机制已经自动注册了,不需要手动加载

从中我们会产生 2 个疑问

  1. com.mysql.jdbc.Driver 不应该是 mysql-connector-java 5.1.49 的吗,怎么会被弃用
  2. SPI 机制是什么,com.mysql.cj.jdbc.Driver 什么时候加载的

我们先来看问题 2,关于 SPI 机制可查看

记一次 JDK SPI 配置不生效的问题 → 这么简单都不会,还是回家养猪吧

DriverManager 有静态代码块

static {
    loadInitialDrivers();
    println("JDBC DriverManager initialized");
}

loadInitialDrivers() 中有这样一段代码

loadInitialDrivers

自动加载了驱动,而驱动类中往往有类似如下代码

驱动类注册驱动实例

将驱动实例注册给 DriverManager,所以不需要再去手动加载驱动类了

从 JDBC 4.0 开始,JDBC 驱动支持自动加载功能,不再需要调用 Class.forName 来加载驱动

我们回到问题 1,同步的告警信息

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.

肯定是 mysql-connector-j 8.0.33 告警出来的,因为 mysql-connector-java 5.1.49 没有类

com.mysql.cj.jdbc.Driver

对不对?全局搜索下

This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'

同步告警信息出处

点进去,我们会发现 mysql-connector-j 8.0.33 也有类

com.mysql.jdbc.Driver

大家看仔细了,这个 Driver 是没有把自己的实例注册进 java.sql.DriverManager

mysql8驱动com_mysql_jdbc_Driver类

这说明什么,说明是从 mysql-connector-j 8.0.33 加载的类:com.mysql.jdbc.Driver,而不是从 mysql-connector-java 5.1.49 加载

我们来捋一捋整个同步流程

  1. 通过 SPI 机制,会加载文件 META-INF/services/java.sql.Driver 中配置的类

    mysql-connector-j 8.0.33 的 java.sql.Driver 文件内容

    mysql8驱动java_sql_Driver

    mysql-connector-java 5.1.49 的 java.sql.Driver 文件内容

    mysql5驱动_java_sql_Driver

    类加载器加载 com.mysql.cj.jdbc.Driver 的时候,毫无疑问找到的肯定是 mysql-connector-j 8.0.33 jar包中的,而加载 com.mysql.jdbc.Driver 的时候,类加载器找到的却是 mysql-connector-j 8.0.33 jar包中的,而非 mysql-connector-java 5.1.49 jar包中的,所以告警了

  2. 代码中手动调用 Class.forName("com.mysql.jdbc.Driver"); 进行类加载,根据 双亲委派模型,已经加载过的类不会再加载,所以相当于没做任何操作

    前面的告警信息不是这里触发出来的!!!不信的话可以注释掉该行代码执行下,你们会发现仍有同样的告警信息

  3. 从 MySQL5 查数据,用的驱动实际是 com.mysql.cj.jdbc.Driver

    连接mysql5的实际驱动

    因为 DriverManager 中合适的驱动只有这一个

  4. 代码中手动调用 Class.forName("com.mysql.cj.jdbc.Driver"); 进行类加载,根据 双亲委派模型,已经加载过的类不会再加载,所以相当于没做任何操作

  5. 从 MySQL8 查数据,用的驱动毫无疑问也只能是 com.mysql.cj.jdbc.Driver

所以整个同步,用的都是 mysql-connector-j 8.0.33 下的驱动,mysql-connector-java 5.1.49 压根就没用到,是不是在你们的意料之外?

小孩 震惊

所以如何实现我们最初的想法?

如何用 mysql-connector-java 5.1.49 从 MySQL 5.7.36 查数据后,用 mysql-connector-j 8.0.33 将数据插入 MySQL 8.0.30

maven-shade-plugin

甲方扔给两个存在包名与类名均相同的Jar包,要在工程中同时使用怎么办? 中谈到了好些解决办法,但 maven-shade-plugin 相对而言是最优解,其具体使用可参考

maven 插件之 maven-shade-plugin,解决同包同名 class 共存问题的神器

那如何应该到当前案例中来了,其实很简单,只需要用到 maven-shade-plugin 的 重定位 class 功能即可,请看我表演

  1. 对 mysql-connector-j 8.0.33 进行 class 重定位

    新建一个工程 mysql-jdbc,没有任何代码和配置文件

    mysql-jdbc8

    只有一个 pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.qsl</groupId>
        <artifactId>mysql-jdbc8</artifactId>
        <version>8.0.33</version>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>com.mysql</groupId>
                <artifactId>mysql-connector-j</artifactId>
                <version>8.0.33</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <version>3.6.0</version>
                    <executions>
                        <execution>
                            <!-- 和 package 阶段绑定 -->
                            <phase>package</phase>
                            <goals>
                                <goal>shade</goal>
                            </goals>
                            <configuration>
                                <relocations>
                                    <relocation>
                                        <pattern>com.mysql.jdbc</pattern>
                                        <shadedPattern>com.mysql.jdbc8</shadedPattern>
                                    </relocation>
                                </relocations>
                                <filters>
                                    <filter>
                                        <artifact>com.qsl:mysql-jdbc8</artifact>
                                        <excludes>
                                            <exclude>META-INF/*.*</exclude>
                                        </excludes>
                                    </filter>
                                </filters>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>
    

    mvn install 一下,将重新打包后的 jar 部署到本地仓库

    mysql-jdbc8_8_0_30

  2. 调整示例代码的 maven 依赖

    mysql-connector-j 8.0.33 调整成 mysql-jdbc8 8.0.33,mysql-connector-java 5.1.49 原样保留

    <dependencies>
        <dependency>
            <groupId>com.qsl</groupId>
            <artifactId>mysql-jdbc8</artifactId>
            <version>8.0.33</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
    </dependencies>
    
  3. 调整同步代码

    去掉手动加载驱动,增加 connection 驱动信息版本输出

    public static void main(String[] args) throws Exception {
        String url5 = "jdbc:mysql://192.168.2.118:3307/qsl_datax?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
        String url8 = "jdbc:mysql://192.168.2.118:3311/sql_db?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
        Properties pro = new Properties();
        pro.put("user", "root");
        pro.put("password", "123456");
        // 建立连接
        Connection conn5 = DriverManager.getConnection(url5, pro);
        // 查数据
        Statement statement = conn5.createStatement();
        System.out.println("conn5 driver version: " + conn5.getMetaData().getDriverVersion());
        ResultSet resultSet = statement.executeQuery("SELECT * FROM qsl_datax_source");
        StringBuilder insertSql = new StringBuilder("INSERT INTO qsl_datax_source(id,username,password,birth_day,remark) VALUES ");
        while (resultSet.next()) {
            // 拼接sql
            insertSql.append("(")
                    .append(resultSet.getLong("id")).append(",")
                    .append("'").append(resultSet.getString("username")).append("',")
                    .append("'").append(resultSet.getString("password")).append("',")
                    .append("'").append(resultSet.getString("birth_day")).append("',")
                    .append("'").append(resultSet.getString("remark")).append("'")
                    .append("),");
        }
        // 因为mysql5和mysql8的账密是一样的,所以用的同一个 pro
        Connection conn8 = DriverManager.getConnection(url8, pro);
        System.out.println("conn8 driver version: " + conn8.getMetaData().getDriverVersion());
        Statement stmt = conn8.createStatement();
        int count = stmt.executeUpdate(insertSql.substring(0, insertSql.length() - 1));
        System.out.println("新插入记录数:" + count);
    
        resultSet.close();
        statement.close();
        stmt.close();
        conn5.close();
        conn8.close();
    }
    

处理就算完成,我们执行一下看结果

maven-shade-plugin改造后执行结果

之前的警告确实没了,但新的问题又来了:为什么驱动用的是同一个,mysql-connector-java 5.1.49 中的驱动为什么没有被用到?

一个bug改一天

mysql-connector-java 5.1.49 中的 com.mysql.jdbc.Driver 肯定是被正常加载了,并且注册到了 DriverManager 中,这点大家认同不?(不认同也没关系,后面会得到证明)那它为什么没有被使用了,我们需要跟一下 DriverManager.getConnection 的源码了;源码跟进去比较简单,我就带你们一步一步跟了,最终回来到如下方法

java.sql.DriverManager#getConnection(java.lang.String, java.util.Properties, java.lang.Class<?>)

这个方法里面有这么一段代码

for(DriverInfo aDriver : registeredDrivers) {
    // If the caller does not have permission to load the driver then
    // skip it.
    if(isDriverAllowed(aDriver.driver, callerCL)) {
        try {
            println("    trying " + aDriver.driver.getClass().getName());
            Connection con = aDriver.driver.connect(url, info);
            if (con != null) {
                // Success!
                println("getConnection returning " + aDriver.driver.getClass().getName());
                return (con);
            }
        } catch (SQLException ex) {
            if (reason == null) {
                reason = ex;
            }
        }

    } else {
        println("    skipping: " + aDriver.getClass().getName());
    }

}

我们打个断点跟一下(com.mysql.cj.jdbc.Driver 排在 com.mysql.jdbc.Driver 前面!!!)

debug_驱动列表

isDriverAllowed 作用是检查一个给定的Driver对象是否被允许通过指定的ClassLoader加载,我们不需要关注,而我们需要关注的是

Connection con = aDriver.driver.connect(url, info);

跟进去来到 com.mysql.cj.jdbc.NonRegisteringDriver#connect

debug_connect

感兴趣的可以继续跟进 ConnectionUrl.acceptsUrl(url),但我觉得没必要了,很明显就是根据正则表达式去匹配 url,看看是否适配,因为 MySQL5 的 url 与 MySQL8 的 URL 格式一致

String url5 = "jdbc:mysql://192.168.2.118:3307/qsl_datax?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
String url8 = "jdbc:mysql://192.168.2.118:3311/sql_db?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai";

因为 com.mysql.cj.jdbc.Driver 排在 com.mysql.jdbc.Driver 前面,所以用它连接了 MySQL5 和 MySQL8,前面的问题

为什么驱动用的是同一个,mysql-connector-java 5.1.49 中的驱动为什么没有被用到?

是不是就清楚了?你们可能又有疑问了:为什么不是 com.mysql.jdbc.Driver 排在前面?这个跟类加载的顺序有关,超出了本文范围,你们自行去查阅。那还能实现最初的目的吗

用 mysql-connector-java 5.1.49 从 MySQL 5.7.36 查数据后,用 mysql-connector-j 8.0.33 将数据插入 MySQL 8.0.30

肯定是能的,看我调整下代码

public static void main(String[] args) throws Exception {
    String url5 = "jdbc:mysql://192.168.2.118:3307/qsl_datax?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
    String url8 = "jdbc:mysql://192.168.2.118:3311/sql_db?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
    Properties pro = new Properties();
    pro.put("user", "root");
    pro.put("password", "123456");

    // 建立连接
    Driver driver5 = getDriver("com.mysql.jdbc.Driver");
    Connection conn5 = driver5.connect(url5, pro);
    // 查数据
    Statement statement = conn5.createStatement();
    System.out.println("conn5 driver version: " + conn5.getMetaData().getDriverVersion());
    ResultSet resultSet = statement.executeQuery("SELECT * FROM qsl_datax_source");
    StringBuilder insertSql = new StringBuilder("INSERT INTO qsl_datax_source(id,username,password,birth_day,remark) VALUES ");
    while (resultSet.next()) {
        // 拼接sql
        insertSql.append("(")
                .append(resultSet.getLong("id")).append(",")
                .append("'").append(resultSet.getString("username")).append("',")
                .append("'").append(resultSet.getString("password")).append("',")
                .append("'").append(resultSet.getString("birth_day")).append("',")
                .append("'").append(resultSet.getString("remark")).append("'")
                .append("),");
    }
    // 因为mysql5和mysql8的账密是一样的,所以用的同一个 pro
    Driver driver8 = getDriver("com.mysql.cj.jdbc.Driver");
    Connection conn8 = driver8.connect(url8, pro);
    System.out.println("conn8 driver version: " + conn8.getMetaData().getDriverVersion());
    Statement stmt = conn8.createStatement();
    int count = stmt.executeUpdate(insertSql.substring(0, insertSql.length() - 1));
    System.out.println("新插入记录数:" + count);

    resultSet.close();
    statement.close();
    stmt.close();
    conn5.close();
    conn8.close();
}

private static Driver getDriver(String driverClassName) {
    Enumeration<Driver> drivers = DriverManager.getDrivers();
    while (drivers.hasMoreElements()) {
        Driver driver = drivers.nextElement();
        if (driver.getClass().getName().equals(driverClassName)) {
            return driver;
        }
    }
    throw new RuntimeException("未找到驱动:" + driverClassName);
}

执行一下看结果

改造成功_执行结果

此时我就想说一句:还有谁?

还有谁

总结

  1. 示例代码:mysql-driver-demo

    不包括 mysql-jdbc8 的代码

  2. 就 MySQL 而言,mysql-connector-j 8 驱动兼容 MySQL 5.5、5.6、5.7,实际工作中是可以用 mysql-connector-j 8 去连 MySQL 5.7的

  3. SQL Server 就存在驱动不兼容的情况

    Microsoft JDBC Driver for SQL Server 支持矩阵

    SQLServer驱动兼容情况

  4. maven-shade-plugin 来实现多版本驱动的共存,简单高效,值得掌握!

    maven 插件之 maven-shade-plugin,解决同包同名 class 共存问题的神器