Oracle JDBC连接异常:误加载MySQL驱动问题求助
解决多JDBC驱动共存时,Oracle连接被MySQL驱动错误拦截的问题
问题背景
你在尝试用sys用户(需SYSDBA身份)通过JDBC连接Oracle数据库时遇到了驱动冲突问题:
- 项目同时引入了
ojdbc6.jar(Oracle驱动)和mysql-connector-java-8.0.11.jar(MySQL驱动) - 执行Oracle连接代码时,MySQL驱动错误地尝试解析Oracle的连接URL,抛出了URL格式错误的异常
- 移除MySQL驱动后,能得到预期的Oracle错误
ORA-28009(提示连接SYS需用SYSDBA/SYSOPER身份) - 需要保留两个驱动的同时解决该问题
原始连接代码
private static Connection createConnectionOracle() { Connection conn = null; try { Class.forName("oracle.jdbc.driver.OracleDriver"); conn = DriverManager.getConnection( "jdbc:oracle:thin:@ (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.151)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl)))", "sys", "sys" ); } catch (Exception e) { e.printStackTrace(); } return conn; }
实际错误栈(MySQL驱动拦截导致)
java.sql.SQLNonTransientConnectionException: Cannot load connection class because of underlying exception: com.mysql.cj.exceptions.WrongArgumentException: Malformed database URL, failed to parse the main URL sections. at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:108) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:95) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:87) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:61) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:71) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:79) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:131) at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:231) at java.sql.DriverManager.getConnection(DriverManager.java:664) at java.sql.DriverManager.getConnection(DriverManager.java:247) at com.dataguise.discoverAgent.util.Test.createConnectionOracle(Test.java:399) at com.dataguise.discoverAgent.util.Test.main(Test.java:29) Caused by: com.mysql.cj.exceptions.UnableToConnectException: Cannot load connection class because of underlying exception: com.mysql.cj.exceptions.WrongArgumentException: Malformed database URL, failed to parse the main URL sections. at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:59) at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:103) ... 5 more Caused by: com.mysql.cj.exceptions.WrongArgumentException: Malformed database URL, failed to parse the main URL sections. at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:59) at com.mysql.cj.conf.ConnectionUrlParser.parseConnectionString(ConnectionUrlParser.java:139) at com.mysql.cj.conf.ConnectionUrlParser.<init>(ConnectionUrlParser.java:129) at com.mysql.cj.conf.ConnectionUrlParser.parseConnectionString(ConnectionUrlParser.java:118) at com.mysql.cj.conf.ConnectionUrl.getConnectionUrlInstance(ConnectionUrl.java:179) at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:201) ... 4 more
预期错误栈(移除MySQL驱动后)
java.sql.SQLException: ORA-28009: connection as SYS should be as SYSDBA or SYSOPER at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:445) at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:389) at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:382) at oracle.jdbc.driver.T4CTTIfun.processError(T4CTTIfun.java:600) at oracle.jdbc.driver.T4CTTIoauthenticate.processError(T4CTTIoauthenticate.java:445) at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:450) at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192) at oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:380) at oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:760) at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:401) at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:546) at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:236) at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32) at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:521) at java.sql.DriverManager.getConnection(DriverManager.java:664) at java.sql.DriverManager.getConnection(DriverManager.java:247) at com.dataguise.discoverAgent.util.Test.createConnectionOracle(Test.java:399) at com.dataguise.discoverAgent.util.Test.main(Test.java:29)
问题原因
DriverManager的工作机制是遍历所有注册的JDBC驱动,依次尝试用每个驱动去解析连接URL。MySQL的驱动在这里错误地认为自己可以处理Oracle的URL(没有正确判断URL前缀),导致它先于Oracle驱动抛出异常,中断了后续的驱动尝试流程。
解决方案
下面提供三种可靠的解决方法,按推荐程度排序:
1. 使用Oracle DataSource直接获取连接(推荐)
完全绕过DriverManager的驱动遍历逻辑,直接使用Oracle官方提供的OracleDataSource来创建连接,同时还能顺便解决ORA-28009的问题(指定SYSDBA身份):
private static Connection createConnectionOracle() { Connection conn = null; try { OracleDataSource ods = new OracleDataSource(); // 设置Oracle连接URL ods.setURL("jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.151)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl)))"); ods.setUser("sys"); ods.setPassword("sys"); // 指定SYSDBA身份,解决ORA-28009错误 ods.setInternalLogon("sysdba"); conn = ods.getConnection(); } catch (Exception e) { e.printStackTrace(); } return conn; }
2. 直接实例化Oracle驱动并调用connect方法
不依赖DriverManager的自动选择,手动使用Oracle驱动处理连接请求:
private static Connection createConnectionOracle() { Connection conn = null; try { // 直接创建Oracle驱动实例 oracle.jdbc.driver.OracleDriver oracleDriver = new oracle.jdbc.driver.OracleDriver(); Properties connectionProps = new Properties(); connectionProps.setProperty("user", "sys"); connectionProps.setProperty("password", "sys"); // 添加SYSDBA身份属性 connectionProps.setProperty("internal_logon", "sysdba"); String oracleUrl = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.151)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl)))"; conn = oracleDriver.connect(oracleUrl, connectionProps); } catch (Exception e) { e.printStackTrace(); } return conn; }
3. 调整驱动注册顺序(可选,可靠性稍低)
JDBC4.0+会自动加载META-INF/services/java.sql.Driver中的驱动类。可以通过以下方式让Oracle驱动优先注册:
- Maven依赖调整:在
pom.xml中将Oracle的依赖放在MySQL依赖之前,类加载器会优先加载靠前的驱动 - 手动注册驱动:在应用启动时先注册Oracle驱动,再注册MySQL驱动:
static { try { // 先注册Oracle驱动 Class.forName("oracle.jdbc.driver.OracleDriver"); // 再注册MySQL驱动 Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
注意:这种方法可能受类加载器策略影响,不如前两种方法稳定。
内容的提问来源于stack exchange,提问作者Ajay Singh
相关产品推荐
相关产品推荐

