One of the great additions in version 4 of JDBC You don't have to explicitly load the
driver by calling Class.forName anymore. When your application attempts to connect the database for the first time, DriverManager automatically loads the driver found in
the application CLASSPATH.
My question is how? What if there are multiple drivers in the classpath?
One thing I can guess is that on parsing the connection URL whether driver needed is of JDBC or ODBC can be figured out but how can one say out of multiple jdbc compliant drivers which one is to be selected for the database I am using? (lets say I am using MySql and I need MySql-Connector driver). Is there any static mapping of such database drivers in JVM?
Every JDBC 4 compliant driver has a file in its jar called META-INF/services/java.sql.Driver, in that file it will list its implementation(s) of java.sql.Driver. When you request a connection, DriverManager will use the ServiceLoader to find all(!) copies of META-INF/services/java.sql.Driver in the classpath and will then load all classes listed. When a java.sql.Driver class is loaded, it has to register itself with the DriverManager, so the DriverManager loads all classes using the service loader, and each Driver implementation registers itself.
When you request a connection from DriverManager, the DriverManager will iterate over all registered drivers asking them for a Connection. The driver will use the JDBC url to check if it's a protocol it supports (eg Jaybird/Firebird JDBC checks if the url starts with "jdbc:firebirdsql:" or "jdbc:firebird:"). If the driver does not support the protocol, it will return null, if it does support the protocol it will either return an established connection, or it will throw an SQLException (eg if you made an error in the URL, or it couldn't connect). If all drivers return null (none support the protocol), then DriverManager will throw an SQLException with error "No suitable driver found for <url>"
So, having multiple drivers on the classpath does not matter as long as they support different protocols, however if there are multiple drivers for the same database (or at least: same protocol prefixes), it will use the first in the list of drivers. Depending on the Java version, if that driver fails with an SQLException, it will continue with the next driver (at least Java 5 and later), or stop trying and throw the exception (I believe this was in Java 1.4 or maybe even earlier).
Some information about JDBC4 driver loading taken from : http://www.onjava.com/2006/08/02/jjdbc-4-enhancements-in-java-se-6.html
When the method getConnection is called, the DriverManager will
attempt to locate a suitable driver from among the JDBC drivers that
were loaded at initialization and those loaded explicitly using the
same class loader as the current application.
The DriverManager methods getConnection and getDrivers have been
enhanced to support the Java SE Service Provider mechanism (SPM).
According to SPM, a service is defined as a well-known set of
interfaces and abstract classes, and a service provider is a specific
implementation of a service. It also specifies that the service
provider configuration files are stored in the META-INF/services
directory. 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. For example, to load
the JDBC driver to connect to a Apache Derby database, the
META-INF/services/java.sql.Driver file would contain the following
entry:
org.apache.derby.jdbc.EmbeddedDriver
Now coming to your question.
My question is how? What if there are multiple drivers in the
classpath?
As a class loader rule, any class found first will be loaded and if it is already loaded then will not be reloaded by the class loader.
Answer for your question will get it from java.sql.DriverManager java class ,method loadInitialDrivers.
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers");
}
});
If program found multiple jdbc driver,it will use below logic to take exact driver
String[] driversList = drivers.split(":");
println("number of Drivers:" + driversList.length);
for (String aDriver : driversList) {
try {
println("DriverManager.Initialize: loading " + aDriver);
Class.forName(aDriver, true,
ClassLoader.getSystemClassLoader());
} catch (Exception ex) {
println("DriverManager.Initialize: load failed: " + ex);
}
Related
I am trying to connect to Impala using keytab file but I didn't find exact URL to connect with keytab. I have gone through Cloudera documentation, but it does not mention using keytab file with principal to connect to Impala. What will be the JDBC URL to connect to Impala using keytab file?
As described in the User Guide, section "Using Kerberos", Impala JDBC driver supports three methods of getting Kerberos Subject:
...The driver tries to obtain the Subject from the current thread's inherited AccessControlContext. If the AccessControlContext contains
multiple Subjects, the driver uses the most recent Subject.
The driver checks the java.security.auth.login.config system property for a JAAS configuration. If a JAAS configuration is
specified, the driver uses that information to create a LoginContext
and then uses the Subject associated with it.
The driver checks the KRB5_CONFIG and KRB5CCNAME system environment variables for a Kerberos ticket cache. The driver uses the information
from the cache to create a LoginContext and then uses the Subject
associated with it.
You can control which method driver will be using via KrbAuthType parameter in connection URL, otherwise it will try each method one by one.
So, all you should do to use keytab file (method# 2) is
create a jaas.conf file specifying keytab location, principal, etc.
set system property java.security.auth.login.config in your program (or use
JVM startup argument -Djava.security.auth.login.config=</some-path-to/jaas.conf>) pointing to the location of that jaas.conf, and
in your JDBC connection URL, set ...AuthMech=1;KrbRealm=<YOUR-REALM.COM>;KrbHostFQDN=your.impalad.host.com;KrbServiceName=<impala-service-principal> for Kerberos authentication
...before trying to connect.
Alternatively, kinit using your keytab so that ticket cache contains necessary TGT before calling your Java application (essentially, use method 3 above).
I am trying to open a JDBC connection to a Google Cloud Spanner database, but I get the following error message:
java.lang.IllegalArgumentException: A project ID is required for this
service but could not be determined from the builder or the
environment. Please set a project ID using the builder.
My JDBC URL is as follows:
jdbc:cloudspanner://localhost;Project=project-id;Instance=instance-id;Database=database-name;PvtKeyPath=path-to-key-file
If I remove the Project property from the URL, I get the following exception:
java.sql.SQLNonTransientConnectionException: [Simba]JDBC
Connection Refused: [Simba]JDBC Required Connection Key(s):
Project; [Simba]JDBC Optional Connection Key(s): Language,
Mode
So it seems that the driver does pick up my Project ID, but somehow does not accept it. I have checked and double checked that my project id does equal the project id that I created on Google, I have also tried to change the value to the project name instead of the project id, but to no avail.
Does anyone have a URL example that works?
EDIT: It appears to be related to the reference to the private key file. If I make an environment variable GOOGLE_APPLICATION_CREDENTIALS pointing to my private key file, the connection can successfully be made. If I remove this environment variable, I get the above exception.
Which version of the driver are you using? In the latest version, if you are specifying the path to the credentials file in the URL then you need not set GOOGLE_APPLICATION_CREDENTIALS.
As the JDBC Driver supplied by Google is severely limited (does not support DML and DDL statemetns), I have written my own JDBC Driver. The driver is designed to work with JPA/Hibernate-enabled applications. The driver can be found here: https://github.com/olavloite/spanner-jdbc
This driver supports the same kind of URL's as the driver supplied by Google, including the PvtKeyPath property.
Good time!
First of all, here is my environment:
Java 1.7
Tomcat 7
Oracle UCP connection pool
Thin JDBC driver
Oracle 10g database with RAC and SCAN (some information)
I need to configure the Oracle FCF feature. There are several articles about it's configuration: Spring documentation (1), complete example (2), ...
I've performed all the steps described in the article (1) and I've also configured a UCP logging where I can see that FCF is actually enabled.
What is confusing for me is the following statement fro the second article:
FAST CONNECTION FAILOVER PREREQUISITES
...
5.) The JVM in which your JDBC instance is running must have
* oracle.ons.oraclehome set to point to your ORACLE_HOME. For example:
*
* -Doracle.ons.oraclehome=C:\oracle\product\10.2.0\db_1
...
Question:
My Oracle database (RAC) is located at a remote server and I use a thin JDBC driver, thus what should I do here (Do I really need to set uop this parameter, and, if yes, than how)? There is no point in the first article about configuring such a JVM parameter, it is only said that I need to set up the 'ONSConfiguration' parameter of a datasource where I should list all the RAC nodes...
UPDATE 1:
Also from the second article:
CLIENT-SIDE ONS CONFIGURATION
...
(2) ONS daemon on the client side
Example ons.config file for a client:
...
At the beginning of this article it is said that the 'client-side' is a java-based application, while the 'server-side' is a database (RAC). It is really required to creare the 'ons.config' file on a java-based-application-side in case of using a thin JDBC driver?
UDPADE 2:
From the Oracle documentation:
Remote Configuration
UCP for JDBC supports remote configuration of ONS through the SetONSConfiguration pool property. The ONS property value is a string that closely resembles the content of an ons.config file. The string contains a list of name=value pairs separated by a new line character (\n). The name can be: nodes, walletfile, or walletpassword. The parameter string should at least specify the ONS configuration nodes attribute as a list of host:port pairs separated by a comma. SSL would be used when the walletfile attribute is specified as an Oracle wallet file.
Applications that use remote configuration must set the oracle.ons.oraclehome system property to the location of ORACLE_HOME before starting the application. For example: java -Doracle.ons.oraclehome=$ORACLE_HOME ...
But how can I set the ORACLE_HOME variable when I have no local installation of Oracle database, that is what the thin driver is about, right?
If you want only use UCP pool , then you just need this setup :
PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
pds.setONSConfiguration("nodes=10.247.43.111:4500, 10.247.43.112:4500");
pds.setFastConnectionFailoverEnabled(true);
where "nodes=10.247.43.111:4500, 10.247.43.112:4500" is list of ons listerers
10.247.43.111:4500 - remote ons listerner on node1
10.247.43.112:4500 - remote ons listerner on node2
etc.
see this good example:
http://www.idevelopment.info/data/Programming/java/jdbc/High_Availability/FastConnectionFailoverExampleThin.java
and this http://docs.oracle.com/cd/B19306_01/java.102/b14355/fstconfo.htm#CEGGDDFJ
ORACLE_HOME needed for local ONS demon connection.
Is there a way to find version number of MS Access using java code. I am using jdbc-odbc bridge to connect with MS Access.
My usecase is to load mdb and accdb driver using JDBC
DriverManager.getConnection("jdbc:odbc:DRIVER={Microsoft Access Driver(.mdb,.accdb);}DBQ=filename")
If i use access 2003 or previous version, accdb driver will not be installed. So, while loading it throws exception. What is the way to resolve it.
Thanks in advance.
Regards,
Ganesan
From the java.sql.Connection you have getMetaData() to get the DatabaseMetaData. Several methods are available here (eg. getDatabaseMajorVersion()) to get version information, if the Driver implement this info.
To use the driver, it must be installed and registered. That you can check:
Enumeration<Driver> driverlist = DriverManager.getDrivers();
while(driverlist.hasMoreElements()) {
System.out.println(driverlist.nextElement().getClass());
}
https://www.tutorialspoint.com/how-to-get-the-list-of-all-drivers-registered-with-the-drivermanager-using-jdbc
This question already has answers here:
The infamous java.sql.SQLException: No suitable driver found
(21 answers)
Closed 7 years ago.
Hi i have found a seemingly common problem, i cant interact with a mysql db. This no suitable driver found keeps happening.
I have followed most threads on this same question, however i was not able to replicate their solution so am posting my own specific question.
(Mostly this thread: I can't load the JDBC driver for MySQL)
My code:
public DBManager(){
try {
//Class.forName("com.mysql.jdbc.Driver");
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
con=DriverManager.getConnection("jdbc:mysql:3306//localhost/test","root","root");
//con=DriverManager.getConnection(c);
if(!con.isClosed()) {
con.close();
}
}
catch (SQLException e) {
e.printStackTrace();
}
Now, i read that on newer drivers you dont need either Class.forName () or registerDriver();
i have tried both and i still cant get it to work.
The thing is am developing on a windows machine, with eclipse Indigo and Connector/J 5.1.17
and deploying (and debugging) on a remote linux with the same Connector.
Am launching my debug sessions with
java -Xdebug -Xrunjdwp:transport=dt_socket,address=8998,server=y -classpath /home/dev/mysql-connector-java-5.1.17-bin.jar -jar devserver.jar
and i get that exception. Any help?
I come from a heavy c# development environment, so if i have to meddle with classpaths and such please try to step it by step as im not very familiar with that.
SQLException: no suitable driver
You will get this exception whenever the DriverManager#getConnection() cannot find a suitable driver for the given connection URL. This in turn happens when the Driver#acceptsURL() has returned false for any of the loaded drivers.
And indeed, your connection URL is wrong:
jdbc:mysql:3306//localhost/test
It should have been:
jdbc:mysql://localhost:3306/test
See also the MySQL JDBC manual.
The JDBC URL format for MySQL Connector/J is as follows, with items in square brackets ([, ]) being optional:
jdbc:mysql://[host][,failoverhost...][:port]/[database] »
[?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]...
If the host name is not specified, it defaults to 127.0.0.1. If the port is not specified, it defaults to 3306, the default port number for MySQL servers.
jdbc:mysql://[host:port],[host:port].../[database] »
[?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]...
If the database is not specified, the connection will be made with no default database.