我正在阅读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.getMajorVersion
,Driver.getMinorVersion
),父记录器(Driver.getParentLogger
)或JDBC兼容性(Driver.jdbcCompliant
)。