当我的类路径中存在Informix JDBC驱动程序时,它似乎在适当的驱动程序获得机会之前拦截并拒绝所有连接字符串。
例如,像jdbc:ghmghmghm
这样完全无意义的连接字符串将导致以下堆栈跟踪:
java.sql.SQLException: Invalid sub-protocol Invalid sub-protocol: 'ghmghmghm'
at com.informix.util.IfxErrMsg.getLocSQLException(IfxErrMsg.java:493)
at com.informix.jdbc.IfxDriver.checkURL(IfxDriver.java:560)
at com.informix.jdbc.IfxDriver.connect(IfxDriver.java:208)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:208)
我的理解是,表现良好的JDBC驱动程序将自己限制为以其魔术前缀开头的连接字符串。 Informix驱动程序是否已损坏,或者我是否有不合理的期望?
更新
如果我只删除Informix驱动程序,但保留所有其他驱动程序,则异常翻转到更加理智
java.sql.SQLException: No suitable driver found for jdbc:ghmghmghm
at java.sql.DriverManager.getConnection(DriverManager.java:596)
at java.sql.DriverManager.getConnection(DriverManager.java:187)
此外,如果Informix驱动程序被删除,则会有特定的有效连接字符串jdbc:sybase:Tds:leeta:5001/leeta_ase1
,但如果存在Informix,则会失败(Informix无效的子协议堆栈跟踪)。
我的结论是Informix并没有正确地拒绝完全不匹配的连接字符串,并且Informix在Sybase连接字符串上获得了第一次破解(但并非我尝试过的所有其他连接字符串类型......)
我的Linux JDK是
java version "1.7.0_91"
OpenJDK Runtime Environment (IcedTea 2.6.3) (7u91-2.6.3-0ubuntu0.14.04.1)
OpenJDK 64-Bit Server VM (build 24.91-b01, mixed mode)
但是我发现错误的连接字符串也导致Windows上的官方Java 8上的Infx跟踪。从未见过Sybase在Windows上被截获,但也许这是一个类路径排序问题。
更新2
我无法重申我的说法,即完全有效的连接字符串被Informix拦截和拒绝。我一定在尝试巧妙的坏字符串,看到Informix堆栈,在响应中删除Informix驱动程序,然后从正确的驱动程序中考虑堆栈是一个胜利(因为它允许快速修复连接字符串)。
我看到了一些改进方法:
DriverManager
(直接实例化驱动程序并在其上调用getConnection()
)DriverManager.getConnection()
的替代品,至少通过Throwable.addSuppressed()
DriverManager.(de)registerDriver()
将错误的actor(静态列表或在运行时动态测试)移动到驱动程序列表的末尾感谢所有反馈!
答案 0 :(得分:4)
这听起来像Informix驱动程序中的一个错误(但最好是一个小错误)。一个表现良好的JDBC驱动程序需要遵循java.sql.Driver.connect(String url, Properties properties)
(强调我的)中定义的期望:
尝试建立与给定URL的数据库连接。司机 如果它意识到它是错误的驱动程序,则应该返回“null” 将连接到给定的网址。这将是常见的,就像JDBC驱动程序一样 管理员被要求连接到给定的URL,它将URL传递给每个URL 依次装载司机。
如果驱动程序是正确的驱动程序,则应该抛出SQLException 将连接到给定的URL,但无法连接到数据库。
java.sql.DriverManager.getConnection
将逐个查询所有已注册驱动程序的connect
方法。如果驱动程序返回null
,它将继续使用下一个驱动程序。如果驱动程序返回连接,则该连接将返回给调用者。如果所有驱动程序都返回null
,则会在“找不到[url]”消息的合适驱动程序时抛出SQLException
。
如果驱动程序抛出SQLException
,则保留最后抛出的异常,并且驱动程序管理器将继续使用下一个驱动程序。如果所有其他驱动程序拒绝与null
的连接尝试,则将抛出最后一个异常而不是“No suitable driver ...”异常。据我所知,在较旧的Java版本中,它实际上会停止尝试其他驱动程序。但是DriverManager
的代码(至少从Oracle / Sun Java 5开始)可以防止这种情况发生,并防止行为不当的驱动程序独占JDBC,并允许尝试使用同一数据库(和协议)的多个驱动程序。
因此,除非你的Java版本有一个不同的DriverManager
实现(在第一个例外停止),它应该继续使用其他注册的驱动程序,如果其中任何一个接受了URL,那么应该没有问题
答案 1 :(得分:1)
最新的Informix JDBC驱动程序版本(JDBC.4.10.JC8DE)修复了该问题。
答案 2 :(得分:0)
根据DriverManager
doc:
作为初始化的一部分,DriverManager类将尝试加载“jdbc.drivers”系统属性中引用的驱动程序类。这允许用户自定义其应用程序使用的JDBC驱动程序。例如,在〜/ .hotjava / properties文件中,您可以指定:
jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver
所以,假设您有3个JDBC驱动程序,这样您的jdbc.drivers
属性如下所示:
jdbc.drivers=com.DriverA:com.DriverB:com.DriverC
如果您致电DriverManager.getConnection("jdbc:driverA:blahblah");
,则DriverManager不知道要使用jdbc.drivers
属性中的哪个驱动程序,因此必须遍历所有驱动程序。
DriverManager.getConnection()可能与此类似:
public Connection getConnection(String url) {
Set<Driver> drivers = // drivers in 'jdbc.drivers' prop
SQLException failure = null;
for(Driver driver : drivers) {
try {
Connection conn = driver.connect(url);
if(conn != null)
return conn;
} catch (SQLException sqle) {
// potentially not trying to connect to the right driver
if(failure == null)
failure = sqle;
}
}
// If we get here, no drivers could connect
if(failure != null)
throw failure;
else // no connection obtained, but no drivers complained
throw new SQLException("No driver found for URL " + url);
}
<强>更新强> (代码示例已更新)
OpenJDK似乎可以容忍驱动程序为其无法识别的协议返回null的情况,并且它还容忍驱动程序为其无法识别的协议抛出异常的情况。
我认为OpenJDK永远不会抛出直接来自Driver的异常,并且如果没有找到该URL的驱动程序,则总是抛出新的SQLException。