Monday, September 1, 2014

How database drivers loaded to system ?

So, we all know how to create a JDBC connection, but what happens when you do
Class.forName (xxxx.xxxx.XXXDriver).

Let's have a look...


The DriverManager class maintains a list of Driver classes that have registered themselves by calling the method DriverManager.registerDriver. All Driver classes should be written with a static section (a static initializer) that creates an instance of the class and then registers it with the DriverManager class when it is loaded. Thus, a user would not normally call DriverManager.registerDriver directly; it should be called automatically by a Driver class when it is loaded. A Driver class is loaded, and therefore automatically registered with the DriverManager.

Most JDBC Driver classes register themselves in their static initializers by calling registerDriver().
registerDriver() is the real call that you hardly ever need to call yourself (unless you write your own JDBC driver).

It can be done using:
Class.forName (com.microsoft.jdbc.sqlserver.SQLServerDriver);
 
Calling the Class.forName automatically creates an instance of a driver and registers it with 
the DriverManager,  so you don't need to create an instance of the class,
If you were to create your own instance, you would be creating an unnecessary duplicate, 
but it would do no harm.

After this it is in the DriverManager's list of drivers and available for creating a connection.
 
So SQLServerDriver written with a static section (a static initializer) that
creates an instance of the class and then registers it with the DriverManager class when it is loaded.


See the given snippet
 
public final class SQLServerDriver implements Driver
{

    static final String driverProperties[] = {
        "databaseName", "user", "password", "serverName", "portNumber", "disableStatementPooling", "integratedSecurity", "lockTimeout", "sendStringParametersAsUnicode", "lastUpdateCount",
        "applicationName", "selectMethod", "loginTimeout", "instanceName", "workstationID", "xopenStates"
    };
    static final String driverPropertiesSynonyms[][] = {
        {
            "database", "databaseName"
        }, {
            "userName", "user"
        }, {
            "server", "serverName"
        }, {
            "port", "portNumber"
        }
    };

  static Properties connProperties;

  static
  {
        try
        {
            DriverManager.registerDriver(new SQLServerDriver());
        }
        catch(SQLException sqlexception)
        {
            sqlexception.printStackTrace();
        }
    }

    public SQLServerDriver()
    {
    }

…….all other methods..

}//end of SQLServerDriver   
 
 
Does loading of two driver classes at same time effect the connection and how to load a driver using static loading:
 
NO, It does not affect database connection it will just register them self with driver manager class by calling
DriverManager.registerDriver() method.
 
Because Vendor specific drivers are implemented in such a way that after loading them using
Class.forName(“”) will automatically register that driver to DriverManager which maintains the 
list of drivers available.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import com.mysql.jdbc.Driver;

public class DBConnection
{
  public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
        Class.forName("com.mysql.jdbc.Driver");
        //com.mysql.jdbc.Driver d= new Driver(); Drivers can be loaded in this way also.
        Connection con= DriverManager.getConnection("jdbc:mysql://localhost:3306/usermgmtdb", "root", "root");
        System.out.println("MySQLConnection object: "+con);
        Enumeration e = DriverManager.getDrivers();
        while (e.hasMoreElements())
        {
              System.out.println("Registered jdbc drivers to driver manager: "+e.nextElement());
        }
  }
}
 
OUTPUT>>
 
MySQLConnection object: com.mysql.jdbc.Connection@18558d2
Registered jdbc drivers to driver manager: sun.jdbc.odbc.JdbcOdbcDriver@14318bb
Registered jdbc drivers to driver manager: com.mysql.jdbc.Driver@530daa


JDBC Drivers can also be loaded in this way also:
 
com.mysql.jdbc.Driver d= new Driver();
This will also load the mysql driver to DriverManager.
 
But Class.forName(“”) is recommended to load the driver.
 
Reason behind it is >>
 
A call to Class.forName("X") causes the class named X to be dynamically loaded (at runtime). 
A call to forName("X") causes the class named X to be initialized (i.e., JVM executes all
its static block after class loading). Class.forName("X") returns the Class object associated with the "X" class.
Class.forName("X") loads the class if it not already loaded. 
The JVM keeps track of all the classes that have been previously loaded.
This method uses the classloader of the class that invokes it. 
The "X" is the fully qualified name of the desired class.
For example,

class AClass { 
    static { 
        System.out.println("static block in AClass");
    }
}

public class Program { 

    public static void main(String[] args) {

        try { 

            Class c   = Class.forName("AClass"); 

        } catch (ClassNotFoundException e) {

        }
    }
}
The output is
static block in AClass
Here is one example that uses returned Class to create an instance of AClass:


class AClass {

  public AClass() {

    System.out.println("AClass's Constructor");
  }

  static { 
    System.out.println("static block in AClass");
  }

}


public class Program { 

  public static void main(String[] args) {

    try { 

      System.out.println("The first time calls forName:");
      Class c   = Class.forName("AClass"); 
      AClass a = (AClass)c.newInstance();

      System.out.println("The second time calls forName:");

      Class c1 = Class.forName("com.xyzws.AClass");

    } catch (ClassNotFoundException e) {
           e.printStacktrace();

    } catch (InstantiationException e) {
         e.printStacktrace();
    } catch (IllegalAccessException e) {            e.printStacktrace();     }   } }
The output is
The first time calls forName:

static block in AClass

AClass's Constructor

The second time calls forName:  

//Calss has been loaded so there is not "static block in AClass" printing out
 
 

 

No comments:

Post a Comment

Thanks for your comments/Suggestions.