This question already has answers here:
How does Class.forName() work?
(4 answers)
Closed 9 years ago.
While doing a simple JDBC connection, all the resources gives the same code that
String driver = "com.mysql.jdbc.Driver";
Statement statement = null;
Class.forName(driver);
Connection conn = DriverManager.getConnection(url + dbName,userName, password);
But we actually nothing do with "Class.forName(driver)". We didn't stored it anywhere.
What is the use of that as we nothing do with Class.forName(driver)'s return.
Class.forName() attempts to load the named class. In early versions of JDBC, this was necessary as the Driver class required the class to be loaded in this way. This hasn't been required for ages.
Leave out the call and nothing bad will happen.
For some reason, tutorials and examples persist with the old way.
The only tiny benefit of loading the class manually is that it tells you exactly what the problem is in case you haven't got the right class in the classpath.
This is the part of com.mysql.jdbc.Driver which registers itself with DriverManager
//
// Register ourselves with the DriverManager
//
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
It should be noted that since ver 1.6 there is no need to explictly load JDBC drivers using Class.forName(), DriverManager can detect JDBC 4.0 Drivers automatically using Service Provider mechanism. JDBC drivers class name is writen in META-INF/services/java.sql.Driver file
The class.forName() causes the ClassLoader to load the class into memory. JDBC driver classes contain a static initializer block that registers the driver with DriverManager for later reference. When you connect DriverManager uses the database parameter to look up the right driver
Class.forName("driver.class"); loads the specified JDBC driver. When the driver loads, it also registers itself with the DriverManager. Hence, when you call DriverManager#getConnection() you're able to establish the Connection through the driver loaded before.
DriverManager#getConnection()
When the method getConnection is called, the DriverManager will attempt to locate a suitable driver from amongst those loaded at initialization and those loaded explicitly using the same classloader as the current applet or application.
Using Class.forName(..) loads the class. Most java.sql.Driver implementations (using a static initializer) register themselves with the java.sql.DriverManager implementation when the class is loaded. See section 9.2 in the JDBC 4.1 specification for details:
JDBC drivers must implement the Driver interface, and the implementation must
contain a static initializer that will be called when the driver is loaded. This
initializer registers a new instance of itself with the DriverManager,
After registration you can create a connection using that driver.
However starting with JDBC 4.0 (Java 6), drivers compliant with the JDBC 4.0 specification no longer need to be loaded this way, as the DriverManager itself will take care of locating and loading JDBC drivers using the ServiceLoader mechanism. See section 9.2.1 of the JDBC 4.1 specification:
The DriverManager.getConnection method has been enhanced to support the
Java Standard Edition Service Provider mechanism. JDBC 4.0 Drivers must include
the file META-INF/services/java.sql.Driver. This file contains the name of
the JDBC driver’s implementation of java.sql.Driver.
Well, it does have one side effect - it loads the driver specified by a string name into the memory.
In Java the classes are loaded only when they're actually needed to be used.
So Class.forName() will cause the class loader to "read" the bytecode and load up the class definition into the memory of the JVM.
Now when this happens, the static initialization block of this class (and Drivers should have one) is executed (it should be static because we don't really create objects of this class).
This static initialization block written so that it registers the driver in the DriverManager.
This is a 'by the book' explanation. Of course this API is not that clear and not obvious.
Its possible to do this explicitly:
Driver driver = (Driver)Class.forName("com.mysql.jdbc.Drivercom.mysql.jdbc.Driver").newInstance();
DriverManager.registerDriver(driver);
Since Java 6 this mechanism should not be used anymore.
Read here about the new way to load up the driver.
Hope this helps
Related
From the Java documentation
In previous versions of JDBC, to obtain a connection, you first had to initialize your JDBC driver by calling the method Class.forName.
Any JDBC 4.0 drivers that are found in your class path are automatically loaded. (However, you must manually load any drivers prior to JDBC 4.0 with the method Class.forName.)
I have a jersey Webservice which connects to SQL Server Express 2016. It has sqljdbc42.jar which is 4.2 driver, in the CLASSPATH
However, if I omit the Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver") call, my DriverManager.getConnection throws a SQLException(No suitable driver found for jdbc:sqlserver://localhost:1433; ....")
The getConnection starts succeeding once I add the Class.forName call.
I am on Java 8.
What am I missing?
UPDATE: I just tried a command line program and it works without the forName. However, from my Eclipse IDE where I am running my REST service as a Tomcat 8.0 Server on localhost, it doesn't work.
The drivers are automatically initialized when the class DriverManager is itself initialized thanks to SPI (Service Provider Interface). Which means that internally it will try to find any file META-INF/services/java.sql.Driver available in the context class loader and for each file found, it will create an instance of the class that is defined in the file which in this case is actually the FQN of the JDBC driver, this is how JDBC drivers are automatically initialized starting from JDBC 4.0.
But this can only work, if your driver is available from the context class loader while initializing the class DriverManager. A good way to ensure that is to make your driver available from a Class Loader high enough in the hierarchy. In your case you should put your driver in tomcat/lib. Indeed, this way your driver will be available from the Common CL which should be high enough. More details about the CL hierarchy in Tomcat here.
I understand that class loading is useful for load the class at runtime with its class name.
However while using JDBC in our project we know which driver we are going to use and mostly driver manager string is hard coded.
My question is: Why are we loading driver using Class.forName("JDBC_DRIVER") here?
Why can't we go ahead adding the driver in class path? since we know which driver jar we are going to use.
I believe Class.forName(JDBC_DRIVER) will load the Driver into DriverManager. Is it the only reason?
Edit 1:
The DriverManager API doc states that
As part of its(DriverManager) initialization, the DriverManager class will attempt to load the driver classes referenced in the "jdbc.drivers" system property.
Applications no longer need to explictly load JDBC drivers using Class.forName(). Existing programs which currently load JDBC drivers using Class.forName() will continue to work without modification.
Then when I use other than oracle driver; do I need to change the driver name string in system property?
First of: with modern JDBC drivers and a current JDK (at least Java 6) the call to Class.forName() is no longer necessary. JDBC driver classes are now located using the service provider mechanism. You should be able to simply remove that call and leave the rest of the code unchanged and it should continue to work.
If you're not using a current JDK (or if you have a JDBC driver that does not have the appropriate files set up to use that mechanism) then the driver needs to be registered with the DriverManager using registerDriver. That method is usually called from the static initializer block of the actual driver class, which gets triggered when the class is first loaded, so issuing the Class.forName() ensures that the driver registers itself (if it wasn't already done).
And no matter if you use Class.forName() or the new service provider mechanism, you will always need the JDBC driver on the classpath (or available via some ClassLoader at runtime, at least).
tl;dr: yes, the only use of that Class.forName() call is to ensure the driver is registered. If you use a current JDK and current JDBC drivers, then this call should no longer be necesary.
The Class.forName(JDBC_DRIVER) call will register your JDBC driver in the DriverManager, so you can address it by url, such as "jdbc:odbc:Database" and so on...
Usually the driver class has static initialization code like this, which is invoked on Class.forName():
public class Driver implements java.sql.Driver {
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
}
You still have to put JDBC driver jar into the classpath.
As an alternative, you can use database specific DataSource, then you can declaratively specify the datasource type, for example in Spring context or in your Web server JNDI. Here is an example.
Putting a class in the classpath is not sufficient to have it loaded by the class loader. And the driver class must be loaded to ensure that it's registered to the JDBC API. BTW, for Class.forName to work, the driver class must be in the classpath.
In many industrial applications, we would like to abstract the data access layer from the rest of code, by pulling such information in a form of a property file/configuration file. In those cases, we might need to use something as you have done.
For e.g. we can use the JDBC interface classes to write the code to access the database, where you could configure the properties by selecting which technology you want to use as a database (e.g. ojdbc driver, or mysql jdbc driver, etc.) In those cases you can load the class using such method.
What is difference between DriverManager.getConnection vs DriverManager.registerDriver() when calling oracle function?
I often used DriverManager.getConnection only but i saw example in oracle site with DriverManager.registerDriver().
So
which i should use when calling oracle function?
When to use DriverManager.registerDriver()?
These two methods are completely different. You should have asked difference between Class.forName() vs DriverManager.registerDriver().
Anyways,
DriverManager.registerDriver() :
Registers the given driver with the DriverManager. A newly-loaded
driver class should call the method registerDriver to make itself
known to the DriverManager.
Ref : http://docs.oracle.com/javase/7/docs/api/java/sql/DriverManager.html#registerDriver(java.sql.Driver)
getConnection() is used for creating the connection once the driver gets loaded
With JDBC 4 The DriverManager methods getConnection and getDrivers have been enhanced to support the Java Standard Edition Service Provider mechanism.
When the method getConnection is called, the DriverManager will attempt to locate a suitable driver from amongst those loaded at initialization and those loaded explicitly using the same classloader as the current applet or application.
You can find the more in the java docs https://docs.oracle.com/javase/8/docs/api/java/sql/DriverManager.html
I understand that class loading is useful for load the class at runtime with its class name.
However while using JDBC in our project we know which driver we are going to use and mostly driver manager string is hard coded.
My question is: Why are we loading driver using Class.forName("JDBC_DRIVER") here?
Why can't we go ahead adding the driver in class path? since we know which driver jar we are going to use.
I believe Class.forName(JDBC_DRIVER) will load the Driver into DriverManager. Is it the only reason?
Edit 1:
The DriverManager API doc states that
As part of its(DriverManager) initialization, the DriverManager class will attempt to load the driver classes referenced in the "jdbc.drivers" system property.
Applications no longer need to explictly load JDBC drivers using Class.forName(). Existing programs which currently load JDBC drivers using Class.forName() will continue to work without modification.
Then when I use other than oracle driver; do I need to change the driver name string in system property?
First of: with modern JDBC drivers and a current JDK (at least Java 6) the call to Class.forName() is no longer necessary. JDBC driver classes are now located using the service provider mechanism. You should be able to simply remove that call and leave the rest of the code unchanged and it should continue to work.
If you're not using a current JDK (or if you have a JDBC driver that does not have the appropriate files set up to use that mechanism) then the driver needs to be registered with the DriverManager using registerDriver. That method is usually called from the static initializer block of the actual driver class, which gets triggered when the class is first loaded, so issuing the Class.forName() ensures that the driver registers itself (if it wasn't already done).
And no matter if you use Class.forName() or the new service provider mechanism, you will always need the JDBC driver on the classpath (or available via some ClassLoader at runtime, at least).
tl;dr: yes, the only use of that Class.forName() call is to ensure the driver is registered. If you use a current JDK and current JDBC drivers, then this call should no longer be necesary.
The Class.forName(JDBC_DRIVER) call will register your JDBC driver in the DriverManager, so you can address it by url, such as "jdbc:odbc:Database" and so on...
Usually the driver class has static initialization code like this, which is invoked on Class.forName():
public class Driver implements java.sql.Driver {
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
}
You still have to put JDBC driver jar into the classpath.
As an alternative, you can use database specific DataSource, then you can declaratively specify the datasource type, for example in Spring context or in your Web server JNDI. Here is an example.
Putting a class in the classpath is not sufficient to have it loaded by the class loader. And the driver class must be loaded to ensure that it's registered to the JDBC API. BTW, for Class.forName to work, the driver class must be in the classpath.
In many industrial applications, we would like to abstract the data access layer from the rest of code, by pulling such information in a form of a property file/configuration file. In those cases, we might need to use something as you have done.
For e.g. we can use the JDBC interface classes to write the code to access the database, where you could configure the properties by selecting which technology you want to use as a database (e.g. ojdbc driver, or mysql jdbc driver, etc.) In those cases you can load the class using such method.
Which is the difference from forName method vs registerDriver to load and register a JDBC driver?
Class.forName() is not directly related to JDBC at all. It simply loads a class.
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).
Note that in JDBC 4 you should not need either of those if your JDBC driver is up-to-date, as drivers can be found using the service location mechanisms instead (i.e. simply leave out that call and open your connection as usual). See the documentaton of DriverManager for details:
The DriverManager methods getConnection and getDrivers have been enhanced to support the Java Standard Edition Service Provider mechanism. JDBC 4.0 Drivers must include the file META-INF/services/java.sql.Driver. This file contains the name of the JDBC drivers implementation of java.sql.Driver. For example, to load the my.sql.Driver class, the META-INF/services/java.sql.Driver file would contain the entry:
my.sql.Driver
Applications no longer need to explictly load JDBC drivers using Class.forName(). Existing programs which currently load JDBC drivers using Class.forName() will continue to work without modification.
Never call DriverManager.registerDriver() method manually. The JDBC spec requires a driver to register itself when the class is loaded, and the class is loaded via Class.forName(). In JDBC 4 the drivers are able to be loaded automatically just by being on the class path.
DriverManager.registerDriver() manually is potentially dangerous since it actually causes the Driver to be registered twice. If your code requires you to deregister a Driver to prevent a memory leak then you would only end up deregistering it once and leave a second instance registered.
In additaion to what Joachim Sauer already mentioned about JDBC 4 drivers, note that in practice you usually want to inject either an EntityManager (JPA) or a pooled DataSource (and use JdbcTemplate of Spring).