DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Enterprise AI Trend Report: Gain insights on ethical AI, MLOps, generative AI, large language models, and much more.

2024 Cloud survey: Share your insights on microservices, containers, K8s, CI/CD, and DevOps (+ enter a $750 raffle!) for our Trend Reports.

PostgreSQL: Learn about the open-source RDBMS' advanced capabilities, core components, common commands and functions, and general DBA tasks.

AI Automation Essentials. Check out the latest Refcard on all things AI automation, including model training, data security, and more.

Related

  • Apache Spark for the Impatient
  • Data Integrity in NoSQL and Java Applications Using Bean Validation
  • Schema Change Management Tools: A Practical Overview
  • Build a Full Stack App With SvelteKit and OceanBase

Trending

  • Distributed Caching: Enhancing Performance in Modern Applications
  • ChatGPT Code Smell [Comic]
  • Securing Cloud Storage Access: Approach to Limiting Document Access Attempts
  • Secure Your API With JWT: Kong OpenID Connect
  1. DZone
  2. Data Engineering
  3. Databases
  4. Using Multiple JDBC Drivers in an Application

Using Multiple JDBC Drivers in an Application

Read this article in order to view a tutorial on how to use multiple JDBC drivers for running queries, stored procedures, etc.

By 
Priya Aggarwal user avatar
Priya Aggarwal
·
Jun. 05, 18 · Tutorial
Like (10)
Save
Tweet
Share
16.4K Views

Join the DZone community and get the full member experience.

Join For Free

For running queries, stored procedures, etc. in a relational/SQL database from a Java application, JDBC drivers are used. These JDBC drivers have been made available by various providers. For a SQL database, all of these providers need to provide an implementation of java.sql.Driver interface. Two such implementations are available as JTDS driver and Microsoft's JDBC driver.

The application may need access to multiple databases, which could be hosting different versions of MS SQL Server. While one driver type can be a better choice for SQL Server 2012, other drivers could provide access to more features in SQL Server 2016. Each implementation has its own benefits and limitations. It may become apt to use different database drivers for different databases

I encountered one such application; it had JTDS and Microsoft's JDBC drivers both in the same application. The application was configured to call multiple stored procedures from multiple databases using these two drivers. All was working fine until we made a @Component bean instead of an @Bean, which blocked the application startup. I tried various hypotheses and was able to find that the problem was with loading multiple JDBC drivers concurrently. The application had a multi-threaded set up to load stored procedures' meta-data.

Although I had found the trigger for the problem, I still wasn't sure about the root cause of it. After a few hours of code debugging, I found the sequence of events that was blocking application start-up — it was a deadlock keeping it from starting up. Let me explain.

When the following statement is executed, it triggers the creation of a database connection. Note that the jdbcCall compile statement is being submitted to an executor service with a threadpool.

executorService.execute(() -> simpleJdbcCall.compile());

This requires loading the jdbc driver class. If two such statements are executed for different database drivers, they trigger the creation of two database connections using two different database drivers. These two database driver classes are 'com.microsoft.sqlserver.jdbc.SQLServerDriver' and 'net.sourceforge.jtds.jdbc.Driver'. Both implement java.sql.Driver interface.

Class-loading requires initializing static class members and running static blocks. Both of these driver classes have a static block, which must be executed in order to create instances of these drivers.

Static block in com.microsoft.sqlserver.jdbc.SQLServerDriver

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

Static block in net.sourceforge.jtds.jdbc.Driver

static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            ;
        }
    }

As shown in the code snippet above, both of these classes register themselves to java.sql.DriverManager by calling DriverManager.registerDriver(..). Since the call for both database sproc compile statement is being executed by different threads, let me call JTDS static block calling thread — Thread-1 and MSSQL driver static block executing thread — Thread-2.

Calling DriverManager class's static method registerDriver triggers DriverManager class loading operation. Now, DriverManager class also has a static block, which needs to be executed as part of class loading routine. FThe following is a snippet from the static block of this class:

static {
  ...
  AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {

                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();
                try{
                    while(driversIterator.hasNext()) {
                        driversIterator.next();
                    }
                } catch(Throwable t) {
                // Do nothing
                }
                return null;
            }
        });
  ...
}

DriverManager class uses Service Locator pattern to find the implementations of java.sql.Driver interface and then attempts to load those classes in its static block. Suppose Thread-1 attempts to calls DriverManager.registerDriver method first (calls are concurrent and not parallel, remember! :) ). Then, Thread-1 will take care of DriverManager class loading and hence execute its static block before it reaches there it will acquire "initiaization lock" of this class (Thread-2 would wait until the DriverManager class is loaded — class loading op started by Thread-1). In DriverManager's static block, it will find class names 'com.microsoft.sqlserver.jdbc.SQLServerDriver' and 'net.sourceforge.jtds.jdbc.Driver' in the following statement:

ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);

Once it has class names, it tries to load these classes and create an instance in the following statement.

driversIterator.next();

The class loading operation for both of these is already in progress by Thread-1 and Thread-2 for JTDS and MSSQL driver respectively. So, when Thread-1 events sequence is like JTDS driver class loading -> running its static block -> DriverManager class loading -> executing DriverManager's static block -> waiting for seeing MSSQL SQLServerDriver class loaded by Thread-2. And Thread-2 events sequence is like MSSQL SQLServerDriver class loading -> running its static block -> waiting for DriverManager class loading to finish by Thread-1.

This sequence of events would look like this:

Events sequence for both threads

From java.sql.DriverManager java documentation

Applications no longer need to explicitly load JDBC drivers using Class.forName(). Existing programs, which currently load JDBC drivers using Class.forName() will continue to work without modification.

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.

The problem is that DataSource class loads drivers using Class.forName() method and hence creates the deadlock.

org.apache.tomcat.jdbc.pool.DataSource

Code for demonstrating this deadlock behavior can be seen here.

Driver (software) application Database Blocks

Published at DZone with permission of Priya Aggarwal. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Apache Spark for the Impatient
  • Data Integrity in NoSQL and Java Applications Using Bean Validation
  • Schema Change Management Tools: A Practical Overview
  • Build a Full Stack App With SvelteKit and OceanBase

Partner Resources


Comments

ABOUT US

  • About DZone
  • Send feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: