Why is JDBC dynamically loaded instead of imported? [duplicate] - java

This question already has answers here:
Why we use Class.forName(“oracle.jdbc.driver.OracleDriver”) while connecting to a database?
(5 answers)
Closed 4 years ago.
In JDBC, I only see examples using
Class.forName("com.mysql.jdbc.Driver", true, cl);
and haven't seen one using
import com.mysql.jdbc.Driver;
Is it because we want to let a driver package be dynamically provided at execution time, so can be known only at execution time?
If we have a fixed driver package known before execution, is it possible to go with the second way? How would you compare the two ways?
Thanks.

I only see examples using
Then you're reading really old stuff about JDBC. This is not useful anymore, for quite a long time. It was necessary to load the driver class to make sure the necessary driver was loaded, and able to handle connections to the provided database URLs, before trying to do so.
The JDBC abstractions are all you need to access a database, and you shouldn't care whether you're dealing with a MySQL driver or an Oracle driver, or whatever. Loading the driver dynamically, at runtime, allows removing the driver jar file from the compile classpath, and making sure you only rely on the standard JDBC classes and interfaces.
Note that importing a class doesn't do anything, other than allowing you to use the simple class name in your code. It's not equivalent to loading and initializing a class, which is what the first snippet does.

Related

Does using a JDBC driver in a Java program work without reflection?

Is it correct that when we dynamically load a .class class file, we need to use reflection to access the methods defined in the class?
When we use a JDBC driver in our Java program,
if I am correct, the JDBC driver is also dynamically loaded behind the scene.
But we never need to use reflection to access the methods defined in the JDBC driver. Instead we import java.sql and access the classes and methods defined in the java.sql.
Under the hood, is there reflection undergoing? If not, how does it work without reflection?
In general, when we dynamically load a .java class file, how can we eliminate or hide the use of reflection to access the methods defined in the class, just like a JDBC driver?
By the way, does a JDBC driver define exactly a class?
Thanks.
JDBC driver needs to implement java.sql.Driver interface (e.g. oracle.jdbc.OracleDriver). Apart from that the JDBC driver code is just plain Java code. It can use reflection or any other Java language feature. It's up to the driver vendor to decide if it's worth it e.g. using classes introduced in Java 8 will make it compatible only with Java 8+.
What is and isn't dynamically loaded depends on the JVM and the implementation of ClassLoader. Certain technologies like OSGI give more flexibility by implementing a ClassLoader that allows for unloading parts of the application.
Loading the JDBC driver class should happen so infrequently, and be cached by JVM, that cost of this one reflective call to load the driver should be negligible. A single SELECT 1 query will be orders of magnitude more expensive than loading the driver bytecode.
Starting with JDBC 4.0 it is no longer necessary to do any reflection-related calls to work with JDBC drivers, as any driver discovered on your class path is loaded automatically.
If your code must support pre-JDBC 4 code, or if your JDBC driver is not located on your class path, you must call Class.forName to load the driver.
Under the hood, is there reflection undergoing?
JDBC 4.0 uses Service Provider mechanism to locate JDBC drivers without doing reflection directly. At some point, however, JDBC driver class needs to be loaded, so a reflection call must be performed.

Why does getting JDBC Connection need Reflection? [duplicate]

What is the actual use of Class.forName("oracle.jdbc.driver.OracleDriver") while connecting to a database? Why cant we just import the same class, instead why we are loading it.
The basic idea behind using Class.forName() is to load a JDBC driver implementation. A (normal) JDBC driver must contain a static initializer that registers an instance of the driver implementation with java.sql.DriverManager:
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
(from JDBC 4.1, section 9.2)
Since JDBC 4.0 however there is a new way to register drivers: the jar of a JDBC driver needs to include a file /META-INF/services/java.sql.Driver which contains the name(s) of the java.sql.Driver implementations in that jar. When you create a connection using the DriverManager, it will use java.util.ServiceLoader to enumerate all /META-INF/services/java.sql.Driver files in the classpath and load all drivers so they get registered.
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.
(from JDBC 4.1, section 9.2.1)
The reasons drivers are loaded this way, is that it allows you to decouple an application from the driver (and database) it uses. This means that you can write, compile and even distribute an application without any drivers, you only need to use the interfaces provided in the java.sql (and javax.sql) package - which is part of Java - without needing to access the implementation directly.
The user of the application then adds a valid JDBC driver to the classpath (and configuring things like a connection string) so the application can actually to connect to a database. Before JDBC 4.0, the user would have to specify the driver name so that the application could load it using Class.forName, with a JDBC 4.0 compliant driver and Java 6 or higher this discovery is automatic.
When you load a driver literally with Class.forName("oracle.jdbc.driver.OracleDriver") it might feel like overkill, but if you keep in mind that it could also be a string pulled from a config file (or from user input) you might start to understand why it is so powerful.
Of course this driver independence is not 100%, especially not if your application uses vendor specific SQL. But the theory is that your application can be database independent. JDBC also provides some additional mechanisms to address this, eg JDBC escapes to provide a common syntax that the driver translates to the specific syntax, and DatabaseMetaData which allows you to discover features, reserved words etc which allow you to create or generate compatible queries.
A couple reasons to use Class.forName("") instead of just referencing the class directly:
Using Class.forName("") gives you more obvious control over where exactly the first attempt to load the specified class will be made in your code. This makes it more obvious where the code will fail (throw an exception) if that class is not present in the classpath when that code runs.
If you simply import the class and then reference it in your code, it becomes slightly less obvious where the code will throw an exception if the class is not present.
Also, using Class.forName("") is a way to get around potential compile-time restrictions. If, for example, the person compiling the code does not (for, let's say, licensing or intellectual property reasons) have access to the class oracle.jdbc.driver.OracleDriver, they may find it easier to compile code which references the class by Class.forName("") rather than directly.
If you do not need to use any methods, fields, or inner classes of the specified class, then Class.forName("") may be the clearest way to express that the only thing desired is to load the class (and have its static initializers run), and nothing else.
I don't think Class.forName exhibits any different functional behavior than referencing the class directly. It uses the calling class' classloader by default, which should be the same classloader that is used when referencing the class directly. There are some overloads to Class.forName("") that let you customize the class loading behavior a bit more.
It`s a legacy way to do so. Importing class you will have extra dependency
From The Java Tutorial:
In previous versions of JDBC, to obtain a connection, you first had to
initialize your JDBC driver by calling the method Class.forName. This
methods required an object of type java.sql.Driver. Each JDBC driver
contains one or more classes that implements the interface
java.sql.Driver.
...
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.)
Sometimes it is required to load a class during the run time. i.e, any class can be loaded into the memory location dynamically while executing the java application. The Class.forName is used to load any given class (within double quotes as String) at run time. For example, when we use IDE, we see there will be a GUI builder which allows us to drag and drop the buttons, text fields, etc. This drag and drop mechanism internally requires certain classes to be loaded at run time.
In the Class.forName (sun.jdbc.odbc.JdbcOdbcDriver), the Class belongs to the package java.lang.Class and the forName() is a static method of the java.lang.Class. The JDBC Drivers (String) will be loaded into the class dynamically at run time and forName method contains static block which creates the Driver class object and register with the DriverManager Service automatically. Since the forName() is static, we call it using the class name (Class).
When we want to execute static block of a class, without creating its object then we can use class.forName(). Most of the work that Driver class do, exists in its static block.
Now what we require in our JDBC connectivity is to get the driver registered with DriverManager and to obtain connections with it, so this can be achieved simply by getting static block executed and there is no requirement to create object of that class. This approach will give a better performance.

What's the difference between com.microsoft.sqlserver.jdbc.SQLServerConnection and java.sql.Connection

I'm having a Maven Web Application on a Tomcat 8 connecting to a SQL Server 2012 Database.
For logging purposes I wanted to use the getClientConnectionID.
Due to the policies of Microsoft it's quite a pain to make their driver work with Maven (I know it's possible and I did it for a while, but in my case it lead to several problems after migrating/sharing the project).
Unfortunately the JTDS-Driver refuses to work with the Database server for unknown reasons.
So right now I've just put the sqljdbc4-4.0.jar into the lib folder of Tomcat and the META-INF/services of the project and since then everything is fine.
Yet after doing more with the database I'm unsure if it's worth to switch and tried to get some information what the actual differences between com.microsoft.sqlserver.jdbc.SQLServerConnection and java.sql.Connection are and if it would make sense to change.
So far I couldn't find useful information. Most pages just refer how to solve issues with each type...
Is there any difference in performance, behaviour or other possibilities which would actually justify switching back?
java.sql.Connection is an interface where com.microsoft.sqlserver.jdbc.SQLServerConnection is an implementation for MS-SQL , you can't compare their performance because the first is just an interface that does nothing where the other is the actual implementation. So you use Connection to maintain abstraction in your code, but effectively you will be using the implementation you provide, which is com.microsoft.sqlserver.jdbc.SQLServerConnection in this case. People usually add those as runtime dependencies so they don't get a polluted namespace.
java.sql.Connection is the interface which is implemented by com.microsoft.sqlserver.jdbc.SQLServerConnection.
Normally you would only program against the interface to be independent of the specific implementation. Then - if you don't rely on some implementation specific behaviour - you can simply exchange the jar with the JDBC driver and your code should still work without any changes.

Why java need Class.forName or dynamic loading?

Say. jdbc driver need Class.forName to exec static block of a class.
Why not just run it as a class field?
Class.forName() is guaranteed to initialize the class at the time you call it. How would you propose to do it? Could you just declare a local variable without assigning it, like com.foo.Driver d;? What about a making it a member variable instead? Would you have to actually assign it? What does the spec say about how and when a class has to be loaded? Do you really want to have to think about that, or just call Class.forName()?
On a related note, it's no longer necessary to do this with many JDBC drivers. The DriverManager now uses the ServiceLoader mechanism to identify and load conforming driver classes.
The whole idea of JDBC is to not be dependant on one specific driver or implementation. The idea is you can use JDBC and configure at runtime any driver which is available. To do this you need to load the driver by name and use the JDBC methods. Unfortunately JDBC doesn't abstract away all the differences between databases like error codes, and switching to a database you haven't tested may not be a good idea.
You could take the view that for all of your libraries, you have them available at compile time and you wouldn't change the database on a wim, without a minimum re-testing and re-deploying your application. In this case linking to a specific driver (instead of using Class.forName) might be a good thing because it would force you (or whomever does this) to put more thought into the change and follow your testing procedures.
It's impractical to use technique for loading JDBC drivers other than reflection.
(Though there are different ways to do it). There's a lot of JDBC drivers and the implementation code may not be available to the app.

How to unload an already loaded class in Java? [duplicate]

This question already has answers here:
Unloading classes in java?
(7 answers)
Closed 6 years ago.
How to unload a class from the class loader, so that I can use the recently changed class on the fly without restarting my application (hot deployment)? Is it possible to do that?
Java rebel reloads changed classes on the fly. See the jrebel website for details. I don't know that I would recommend this for a production environment though, because of performance issues. JRebel on occasion bogs things down momentarily when you've recompiled for a server.
You can't unload a class that is actually in use. But you might want to have a look at platforms like OSGi, if you want to reload or redeploy your application during runtime.
You can't explicitly unload a class.
In principle, you can expicitly reload a class via Classloader.loadClass(). From that moment onwards, all new instances of that class will use the new definition.
In any case, I would proceed with extreme caution...
You would have to create a custom ClassLoader: which returns all Objects wrapped inside a Proxy. The ClassLoader must have a list of all referenced Proxies (keep this list WeakReferenced). If you decide to "unload" and thus "reload" any class, you wait untill the class is loaded, find all Proxy's in your list, and replace the actual object.
There are several problems: you need Reflection, to get all private variables and reset the internal state (see setAccesible on Field). Also multi-threading problems might occour, thus the Proxy must be synchronized: which makes it performing poor.
You can better look for Google's Guice dependency solution, which enables unplugging and reloading modules at runtime. This might be a solution, but way too bloated for a small app. Still: I'm not sure wheter the GC also unloads unused classes.

Categories

Resources