必须使用ojdbc11驱动(如23.7.0.24.07)替代ojdbc8,因其支持Java 17模块系统、声明oracle.jdbc模块名;模块化项目需在module-info.java中显式requires oracle.jdbc;连接URL改用服务名格式(/XE)并配置TLS参数;启动时须添加--add-opens参数放开反射限制。
Oracle JDBC驱动必须用ojdbc11,不是ojdbc8
java 17默认启用模块系统(jep 261),而老版本ojdbc8未声明module-info.java,在jpms下会作为“unnamed module”加载,导致类路径和模块路径混用时出现java.lang.noclassdeffounderror: javax/sql/datasource或module not found: java.xml.bind这类错误。必须使用oracle官方为java 11+编译的ojdbc11(实际兼容java 17),它已正确声明模块名oracle.jdbc。
下载地址:Oracle官网的XE页面或Maven仓库中找com.oracle.database.jdbc:ojdbc11:23.7.0.24.07(版本号需≥21c,推荐用23.x)。不要用Maven Central上非Oracle签名的镜像包,它们常缺模块声明。
模块声明里要显式requires oracle.jdbc
如果你的项目是模块化(有module-info.java),不能只靠--add-modules临时补救。必须在模块描述中写明依赖:
module my.app {
requires java.sql;
requires oracle.jdbc; // 关键:必须这一行
exports com.myapp.db;
}
否则编译期就报错module not found: oracle.jdbc;即使绕过编译强行运行,DriverManager.getConnection()也会因类加载器隔离失败而抛SQLException: No suitable driver。
注意:requires transitive oracle.jdbc不用加——ojdbc11自身不导出其他第三方模块,且你的代码通常只用java.sql接口,不直接调用Oracle特有类。
立即学习“Java免费学习笔记(深入)”;
URL和连接参数要适配Oracle 21c+默认配置
Oracle 21c起默认禁用THIN协议的旧加密套件,若还用jdbc:oracle:thin:@localhost:1521:xe这种老式SID格式,可能连上但握手失败,报IO Error: Connection reset或ORA-28040: No matching authentication protocol。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
改用服务名(service name)并显式指定TLS参数:
-
jdbc:oracle:thin:@localhost:1521/XE(注意斜杠/XE,不是冒号:XE) - 追加
?oracle.net.ssl_version=1.2&oracle.net.encryption_client=REQUIRED(如果DB启用了SSL) - 纯本地开发可加
&oracle.jdbc.javaNetNio=false避免NIO相关偶发超时
Driver类名保持oracle.jdbc.driver.OracleDriver即可,ojdbc11已自动注册,无需Class.forName()。
启动参数别漏掉--add-opens(尤其用HikariCP时)
即使驱动和模块都对了,用HikariCP等连接池时仍可能卡在java.lang.ExceptionInInitializerError,根源是ojdbc11内部反射访问了java.base/java.lang里的私有字段(比如Unsafe初始化逻辑)。JDK 17默认封禁这类反射。
必须加JVM参数放开:
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED
如果用Spring Boot,写在spring-boot-maven-plugin的fork配置里;如果是裸JAR,加到java -jar命令末尾。漏掉任一参数,首次获取连接就会挂住几秒后抛异常。
这个细节极容易被忽略——因为错误堆栈里根本不会提--add-opens,只会显示底层NullPointerException或IllegalAccessError,得顺着线程栈往回翻三屏才看到oracle.jdbc.internal调用了Unsafe.getUnsafe()。

















