记一次Qoder排查mave-shade-plugin只重定向部分package导致的NoSuchMethodError问题,查的还挺快的

开心一刻

小王牙龈发炎,去了个私立牙科就诊

大夫:拔了吧

小王:以前没有拔过牙,我害怕...

大夫:不用紧张,我也是第一次拔

护士问大夫:麻药打嘴里,还是打外面?

大夫:打腿上吧,一会别让他跑了

进了贼窝

问题背景

基于 DataX 实现的离线同步,公司开发环境、测试环境从 Oracle 19c 读取 CLOB 类型的字段都是正常的、

包括已接入的客户都是能正常读取的,但这两天接入的一个新客户,出现了读取失败的问题

java.lang.NoSuchMethodError: oracle.sql.CLOB.<init>(Loracle/jdbc/OracleConnection;[BS)V
	at oracle.jdbc.driver.ClobAccessor.getCLOB_(ClobAccessor.java:240)
	at oracle.jdbc.driver.ClobAccessor.getCLOB(ClobAccessor.java:264)
	at oracle.jdbc.driver.ClobAccessor.getString(ClobAccessor.java:454)
	at oracle.jdbc.driver.GeneratedStatement.getString(GeneratedStatement.java:287)
	at oracle.jdbc.driver.GeneratedScrollableResultSet.getString(GeneratedScrollableResultSet.java:374)
	at com.alibaba.datax.plugin.rdbms.reader.CommonRdbmsReader$Task.buildRecord(CommonRdbmsReader.java:268)
	at com.alibaba.datax.plugin.rdbms.reader.CommonRdbmsReader$Task.transportOneRecord(CommonRdbmsReader.java:238)
	at com.alibaba.datax.plugin.rdbms.reader.CommonRdbmsReader$Task.startRead(CommonRdbmsReader.java:210)
	at com.alibaba.datax.plugin.reader.oraclereader.OracleReader$Task.startRead(OracleReader.java:122)
	at com.alibaba.datax.core.taskgroup.runner.ReaderRunner.run(ReaderRunner.java:57)
	at java.lang.Thread.run(Thread.java:750)
 - java.lang.NoSuchMethodError: oracle.sql.CLOB.<init>(Loracle/jdbc/OracleConnection;[BS)V
	at oracle.jdbc.driver.ClobAccessor.getCLOB_(ClobAccessor.java:240)
	at oracle.jdbc.driver.ClobAccessor.getCLOB(ClobAccessor.java:264)
	at oracle.jdbc.driver.ClobAccessor.getString(ClobAccessor.java:454)
	at oracle.jdbc.driver.GeneratedStatement.getString(GeneratedStatement.java:287)
	at oracle.jdbc.driver.GeneratedScrollableResultSet.getString(GeneratedScrollableResultSet.java:374)
	at com.alibaba.datax.plugin.rdbms.reader.CommonRdbmsReader$Task.buildRecord(CommonRdbmsReader.java:268)
	at com.alibaba.datax.plugin.rdbms.reader.CommonRdbmsReader$Task.transportOneRecord(CommonRdbmsReader.java:238)
	at com.alibaba.datax.plugin.rdbms.reader.CommonRdbmsReader$Task.startRead(CommonRdbmsReader.java:210)
	at com.alibaba.datax.plugin.reader.oraclereader.OracleReader$Task.startRead(OracleReader.java:122)
	at com.alibaba.datax.core.taskgroup.runner.ReaderRunner.run(ReaderRunner.java:57)
	at java.lang.Thread.run(Thread.java:750)

	at com.alibaba.datax.common.exception.DataXException.asDataXException(DataXException.java:48)
	at com.alibaba.datax.core.job.scheduler.processinner.ProcessInnerScheduler.dealFailedStat(ProcessInnerScheduler.java:39)
	at com.alibaba.datax.core.job.scheduler.AbstractScheduler.schedule(AbstractScheduler.java:99)
	at com.alibaba.datax.core.job.JobContainer.schedule(JobContainer.java:532)
	at com.alibaba.datax.core.job.JobContainer.start(JobContainer.java:116)
	at com.alibaba.datax.core.Engine.start(Engine.java:89)
	at com.alibaba.datax.core.Engine.entry(Engine.java:170)
	at com.alibaba.datax.core.Engine.main(Engine.java:209)
Caused by: java.lang.NoSuchMethodError: oracle.sql.CLOB.<init>(Loracle/jdbc/OracleConnection;[BS)V
	at oracle.jdbc.driver.ClobAccessor.getCLOB_(ClobAccessor.java:240)
	at oracle.jdbc.driver.ClobAccessor.getCLOB(ClobAccessor.java:264)
	at oracle.jdbc.driver.ClobAccessor.getString(ClobAccessor.java:454)
	at oracle.jdbc.driver.GeneratedStatement.getString(GeneratedStatement.java:287)
	at oracle.jdbc.driver.GeneratedScrollableResultSet.getString(GeneratedScrollableResultSet.java:374)
	at com.alibaba.datax.plugin.rdbms.reader.CommonRdbmsReader$Task.buildRecord(CommonRdbmsReader.java:268)
	at com.alibaba.datax.plugin.rdbms.reader.CommonRdbmsReader$Task.transportOneRecord(CommonRdbmsReader.java:238)
	at com.alibaba.datax.plugin.rdbms.reader.CommonRdbmsReader$Task.startRead(CommonRdbmsReader.java:210)
	at com.alibaba.datax.plugin.reader.oraclereader.OracleReader$Task.startRead(OracleReader.java:122)
	at com.alibaba.datax.core.taskgroup.runner.ReaderRunner.run(ReaderRunner.java:57)
	at java.lang.Thread.run(Thread.java:750)

提示找不到 CLOB 构造函数

当客户反馈这个问题后,我第一时间在公司环境进行测试,并未出现问题

也反编译了 CLOB.class,其构造函数有好几个

12.2.0.1_CLOB构造函数

怎么就 NoSuchMethodError 了呢?

20240115000802

Qoder 排查

当我陷入迷茫,没有可排查方向时,我想到了 AI,正好前不久接入了 Qoder,抱着试一试的心态,我开始了与 Qoder 的对话

我直接提问:

结合相关上下文分析下,从 oracle 19c 读取 clob 类型的字段,为什么会报错。并附上了异常堆栈信息

开始询问qoder

很快 Qoder 给了回复

qoder分析_23版本CLOB

注意:

为了兼容不同版本的 Oracle,我们同时引入了 ojdbc8 12.2.0.1ojdbc8 23.5.0.24.07

直接依赖这两个的话,依赖会冲突,生效的只会是其中某一个:结合实例看 maven 传递依赖与优先级,难顶也得上丫

所以我们利用 maven-shade-plugin 对 23.5.0.24.07 的 package 进行了重定向:maven 插件之 maven-shade-plugin,解决同包同名 class 共存问题的神器

<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>oracle.jdbc</pattern>
                                <shadedPattern>oracle.jdbc23</shadedPattern>
                            </relocation>
                            <relocation>
                                <pattern>oracle.net</pattern>
                                <shadedPattern>oracle.net23</shadedPattern>
                            </relocation>
                            <relocation>
                                <pattern>oracle.security</pattern>
                                <shadedPattern>oracle.security23</shadedPattern>
                            </relocation>
                        </relocations>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <excludes>
                                    <exclude>META-INF/*.MF</exclude>
                                    <exclude>META-INF/*.txt</exclude>
                                    <exclude>META-INF/*.bin</exclude>
                                    <exclude>META-INF/*.properties</exclude>
                                </excludes>
                            </filter>
                        </filters>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/></div>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Qoder 这个分析一针见血,但他分析反了,我选中 OracleReader.java 的代码

private DataBaseType getDatabaseType() {
    Integer dbVersion = this.originalConfig.getInt(CommonConstant.DB_MAJOR_VERSION);
    if (Objects.isNull(dbVersion)) {
        return DataBaseType.Oracle;
    }
    if (dbVersion >= 23) {
        return DataBaseType.Oracle23;
    }
    return DataBaseType.Oracle;
}

补充道:

dbVersion 的值是19,用的应该是12.2.0.1的 oracle.jdbc.driver.ClobAccessor,不会用 jdbc23

Qoder 继续他的分析

补充19c生效的是12驱动而非23

至此,问题原因是不是已经找到?

我总结下

重定向 23 版本 package 的时候,我们并未对其 oracle.sql 包重定向,所以 classpath 上有两个 oracle.sql.CLOB 类,一个是 12 版本的,一个是 23 版本的

JVM 类加载时如果先加载到 23 版本的 oracle.sql.CLOB,就不会继续加载 12 版本的 oracle.sql.CLOB,那么 12 版本的 ClobAccessor 调用 new CLOB(connection, bytes, short) 时,用到的就是 23 版本的 CLOB,而 23 版本的 CLOB 构造函数 CLOB(OracleConnection conn, byte[] lob_descriptor, short csform) 的 OracleConnection 是什么类型?

oracle.jdbc23.OracleConnection(因为我们将 23 版本的 oracle.jdbc 重定向成 oracle.jdbc23 了),而 ClobAccessor 调用 new CLOB(connection, bytes, short) 时,connection 类型是什么?是不是 12 版本的 oracle.jdbc.OracleConnection

总结就是:12 版本的 ClobAccessor 拿着 oracle.jdbc.OracleConnection 类型的参数去调构造函数,但 JVM 先加载的 23 版本的 CLOB 构造函数只接受 oracle.jdbc23.OracleConnection 类型,参数类型不匹配,所以 NoSuchMethodError

最后我又问了一个问题:

为什么有的环境会出现 java.lang.NoSuchMethodError: oracle.sql.CLOB.(Loracle/jdbc/OracleConnection;[BS)V 问题,有的环境又正常

Qoder 很快给出了回答

为什么有些正常有些不正常

这些影响 classpath 顺序的因素,是不是又触及你们的知识盲区了?

好难 不该学编程的

问题修复

问题原因已经找到,修复自然就简单了,将 23 版本的包都重定向

<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>oracle.jdbc</pattern>
                                <shadedPattern>oracle.jdbc23</shadedPattern>
                            </relocation>
                            <relocation>
                                <pattern>oracle.net</pattern>
                                <shadedPattern>oracle.net23</shadedPattern>
                            </relocation>
                            <relocation>
                                <pattern>oracle.security</pattern>
                                <shadedPattern>oracle.security23</shadedPattern>
                            </relocation>
                            <relocation>
                                <pattern>oracle.sql</pattern>
                                <shadedPattern>oracle.sql23</shadedPattern>
                            </relocation>
                            <relocation>
                                <pattern>oracle.core</pattern>
                                <shadedPattern>oracle.core23</shadedPattern>
                            </relocation>
                            <relocation>
                                <pattern>oracle.jpub</pattern>
                                <shadedPattern>oracle.jpub23</shadedPattern>
                            </relocation>
                        </relocations>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <excludes>
                                    <exclude>META-INF/*.MF</exclude>
                                    <exclude>META-INF/*.txt</exclude>
                                    <exclude>META-INF/*.bin</exclude>
                                    <exclude>META-INF/*.properties</exclude>
                                </excludes>
                            </filter>
                        </filters>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/></div>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

这样 12 版本与 23 版本之间互不干扰,自然就没有 NoSuchMethodError 问题了

当然,重定向也可以简化

<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>oracle</pattern>
                                <shadedPattern>oracle23</shadedPattern>
                            </relocation>
                        </relocations>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <excludes>
                                    <exclude>META-INF/*.MF</exclude>
                                    <exclude>META-INF/*.txt</exclude>
                                    <exclude>META-INF/*.bin</exclude>
                                    <exclude>META-INF/*.properties</exclude>
                                </excludes>
                            </filter>
                        </filters>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/></div>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

只要保证重定向后的包名与其他包名不重名,那就没问题

总结

  1. maven-shade-plugin 很强,很好用,但业务细节仍需注意
  2. AI 是趋势,阻挡不了就好好拥抱,早用早享受
posted @ 2026-07-28 08:51  青石路  阅读(78)  评论(0)    收藏  举报