为什么 DriverManager.getConnection 不使用 Driver 中的"acceptsURL"方法.class



我正在阅读JDBC代码。在DriverManager.getConnection中,我发现它的工作原理是这样的:它试图连接它知道的每个驱动程序,直到它成功。

这是代码:

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());
}
}

但是有一个来自接口驱动程序的"接受URL"的方法:

boolean acceptsURL(String url) throws SQLException;

所以我的问题是,为什么 DriverManager 在进行真正的连接以过滤不相关的驱动程序之前不调用此方法?

或者用代码,也许这样更好?

for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if(isDriverAllowed(aDriver.driver, callerCL) && aDriver.driver.acceptsURL(url)) {
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());
}
}

DriverManager参考实现(OpenJDK)不使用acceptsUrl。这并不一定意味着没有使用它的DriverManager实现。事实上,据我所知,早期的Sun Java实现确实调用了acceptsURL。不调用它的主要原因是 JDBC 规范要求DriverManager无论如何都要在每个注册的驱动程序上调用connect。见下文。

规范或 API 文档中没有任何内容说DriverManager必须使用acceptsURL。JDBC 4.3 规范对此仅说明(第 9.2 节Driver接口):

DriverManager类在需要时调用Driver方法 与已注册的驱动程序交互。Driver界面也 包括方法acceptsURL.DriverManager可以使用这个 确定应将其注册的驱动程序用于哪些的方法 给定的网址。

(强调我的)

请注意,使用单词可以代替必须

随后的一段说:

DriverManager尝试建立连接时,它会调用 该驱动程序的connect方法,并将 URL 传递给驱动程序。如果Driver实现理解 URL,它将返回Connection对象或抛出SQLException(如果连接无法) 对数据库感到生气。如果Driver实现 不理解网址,它会返回null

此外,第 9.4 节DriverManager说:

  • getConnection— JDBC 客户端调用以建立连接的方法。调用包括一个 JDBC URL,该DriverManager传递到其列表中的每个驱动程序,直到找到 一个Driver.connect方法识别 URL的方法。该驱动程序将Connection对象返回给DriverManager,而又返回 将其传递给应用程序。

(强调我的)

我是如何阅读的,无论如何都需要在每个驱动程序上调用Driver.connect,因此实现调用acceptsURL没有意义。

现在,至于为什么JDBC规范是这样写的,我不知道,我自己也是JSR-221(JDBC 4)专家组的成员。当我加入专家组时,实现(和规范)已经是这样了,所以我不知道它的历史。但是,我不确定您在这里会得到比上述不满意答案更好的答案(之所以如此,是因为规范是这样说的)。

但是,如果我不得不猜测,这可能与以下事实有关:对于某些驱动程序来说,确定他们是否可以接受 URL 可能相对复杂或昂贵。在这种情况下,最好只是尝试连接,因为对于拒绝 URL 的驱动程序,成本(或应该)与仅调用acceptsURL相同,而对于实际接受 URL 的驱动程序,如果DriverManager首先调用acceptsURL然后调用connect,则成本将达到两次。

这并不意味着acceptsURL方法完全没有价值。一些应用程序(例如某些查询工具或报告工具)使用它来发现哪些驱动程序将处理特定的URL,因此它们可以查询Driver实现以获取其支持的连接属性(Driver.getPropertyInfo​),以便它们可以使用可用属性填充连接向导。其他程序可以使用它来获取信息,如其版本(Driver.getMajorVersionDriver.getMinorVersion),父记录器(Driver.getParentLogger)或JDBC兼容性(Driver.jdbcCompliant)。

相关内容

最新更新