JDBC连接一般需要以下步骤:
1 加载驱动
Class.forName("com.mysql.jdbc.Driver");
2 获取连接对象
Connection con=
DriverManager.getConnection("jdbc:mysql://localhost:3306/homeworksubmit?user=root&password=root&useUnicode=true&characterEncoding=UTF-8");
3 创建命令对象
Statement stmt =
con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
4 执行sql语句
Result rs=stmt.executeQuery(sql);
但是有疑问的是第一步,没有返回对像,追踪到源码:
Returns the {@code Class} object associated with the class or
interface with the given string name.
equivalent to:
{@code Class.forName(className, true, currentLoader)}
后面几步获取的对象一般都是方便下一步的调用,所以Class.forName()到底如何执行的,以及做了哪些工作,知悉了这些,才能对JDBC连接的理解更加透彻。
在这里首先贴出Driver类源码:
* The Java SQL framework allows for multiple database drivers. Each driver
* should supply a class that implements the Driver interface
*
* <p>
* The DriverManager will try to load as many drivers as it can find and then
* for any given connection request, it will ask each driver in turn to try to
* connect to the target URL.
*
* <p>
* It is strongly recommended that each Driver class should be small and
* standalone so that the Driver class can be loaded and queried without
* bringing in vast quantities of supporting code.
*
* <p>
* When a Driver class is loaded, it should create an instance of itself and
* register it with the DriverManager. This means that a user can load and
* register a driver by doing Class.forName("foo.bah.Driver")
从中可以获取以下信息:
每个驱动类都必须实现Driver接口
当驱动被加载的时候,它首先实例化对象,并将其注册到DriverManager。
com.mysql.jdbc.Driver中的部分代码:
在初始化Driver类的时候,其中的静态代码也会执行,于是乎自动执行下面的语句:
java.sql.DriverManager.registerDriver(new Driver());
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
// ~ Static fields/initializers
// ---------------------------------------------
//
// Register ourselves with the DriverManager
//
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
……
}
就这样,使用forName()初始化Driver后,MySql驱动就自动向DriverManagemer类注册了,使得我们能通过DriverManager获得对MysqL的连接。
贴出registerDriver()源码解释:
* Registers the given driver with the <code>DriverManager</code>.
部分实现代码:
public static synchronized void registerDriver(java.sql.Driver driver)
throws SQLException {
/* Register the driver if it has not already been added to our list */
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver));
} else {
// This is for compatibility with the original DriverManager
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
new DriverInfo(driver),接下来在看一下DriverInfo(driver)类:
DriverInfo非常简单,用于保存Driver的信息,只有3个成员变量,Driver,DriverClass和 DriverClassName,意义非常明显。
在一个类加载入内存的时候,类中的静态初始化过程会执行,这样就完成了驱动程序的注册过程。然后重点看一下建立数据库连接的代码,在getConnection函数中,
/**
* Attempts to establish a connection to the given database URL.
* The <code>DriverManager</code> attempts to select an appropriate driver from
* the set of registered JDBC drivers.
*
* @param url a database url of the form
* <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
* @return a connection to the URL
* @exception SQLException if a database access error occurs
*/
实现函数:
@CallerSensitive
public static Connection getConnection(String url)
throws SQLException {
java.util.Properties info = new java.util.Properties();
return (getConnection(url, info, Reflection.getCallerClass()));
}
到这里基本完成连接了。接下来,考虑一下,源码中说尝试一个合适的驱动从注册的JDBC驱动中,轮询方式,当注册的驱动多了,连接速度会越慢。JDBC连接数据库的速度很慢, 是不是和这种实现方式有关联呢?看一下Driver类:
public class Driver extends NonRegisteringDriver implements java.sql.Driver
看一下NonRegisteringDriver的实现:
public java.sql.Connection connect(String url, Properties info)
throws SQLException {
if (url != null) {
if (StringUtils.startsWithIgnoreCase(url, LOADBALANCE_URL_PREFIX)) {
return connectLoadBalanced(url, info);
} else if (StringUtils.startsWithIgnoreCase(url,
REPLICATION_URL_PREFIX)) {
return connectReplicationConnection(url, info);
}
}
Properties props = null;
if ((props = parseURL(url, info)) == null) {
return null;
}
try {
Connection newConn = new com.mysql.jdbc.Connection(host(props),
port(props), props, database(props), url);
return newConn;
} catch (SQLException sqlEx) {
// Don't wrap SQLExceptions, throw
// them un-changed.
throw sqlEx;
} catch (Exception ex) {
throw SQLError.createSQLException(Messages
.getString("NonRegisteringDriver.17") //$NON-NLS-1$
+ ex.toString()
+ Messages.getString("NonRegisteringDriver.18"), //$NON-NLS-1$
SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
}
}
先parseURL,然后使用Connection去建立连接。parseURL只是简单的字符串分析,主要是分析传入的连接字符串是否满足 “jdbc:mysql://host:port/database“的格式,如果不满足,直接返回null,然后由DriverManager去试验下 一个Driver。如果满足,则建立一个Connection对象建立实际的数据库连接,由此可见刚刚的问题答案是:DriverManager的轮询查询注册的Driver对象的工作方式所带来的性能代价并不是很大,主工作量只是parseURL函数。
源码追溯到这里结束了,剩下的就不去管了。