Jan 14, 2013

Demystifying “Loading JDBC Driver”


Recently while interacting with newbies or say IT aspirants when being asked about simple JDBC questions most of the people were at sea. Question was simple
“While getting JDBC connection in java application what we do is first we call Class.forname(“<driver-name”) and then we call DriverManager.getConnection with appropriate arguments. We do not get any value from Class.forname and return it to DriverManager so how this works.
Class.forName("driver-name");
DriverManager.getConnection(url, user, password);

Most of the people those who answered simply said it will load JDBC driver. Next question was “What does that mean”. Long pause and then again “Will load the driver” J
So now let’s see what happens when we call Class.forname on JDBC driver for MySQL db.
Class.forName("com.mysql.jdbc.Driver");

Following is code snippet from MySQL driver class.
So when we call Class.forname(“com.mysql.jdbc.Driver”) static block of this class will be called
static {
       try {
              java.sql.DriverManager.registerDriver(new Driver());
       }
       catch (java.sql.SQLException E) {
              throw new RuntimeException("Can't register driver!");
       }
       if (DEBUG) {
              Debug.trace("ALL");
       }
}

Looking at the code we understand that Class.forname will call registerDriver method of DriverManager class and will pass instance of Driver class for MySQL to DriverManager. When DriverManger.registerDriver is called it will check for null and if it is not null then it will add this driver in list of registered drivers.
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);
}

When getConnection(url, user, password) is called it will internally call getConnection(url, driverinfo, classLoaded) which will iterate through registered drivers and call connect method on Driver for which which will create and return connection.
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());                               
       }                         
}

So this is how all happens…Happy coding.. J