Class.forName()做了什么?

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函数。

源码追溯到这里结束了,剩下的就不去管了。

你可能感兴趣的:(mysql,jdbc,driver)