Home > OS >  Why does Class.forName not seem to register driver with DriverManager
Why does Class.forName not seem to register driver with DriverManager

Time:04-09

Being new to JDBC, I was taught to use Class.forName to register a driver to DriverManager, which does not seem to work for my code though:

public static void main(String[] args)
{
    System.out.println(DriverManager.drivers().count());

    // clear all loaded drivers
    Iterator<Driver> it = DriverManager.drivers().iterator();

    while (it.hasNext())
    {
        try { DriverManager.deregisterDriver(it.next()); }
        catch (SQLException e) { e.printStackTrace(); }
    }

    System.out.println(DriverManager.drivers().count());

    // register mysql driver with forName
    try { Class.forName("com.mysql.cj.jdbc.Driver"); }
    catch (ClassNotFoundException e) { e.printStackTrace(); }

    System.out.println(DriverManager.drivers().count());

    // register with constructor - works fine
    try { DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver()); }
    catch (SQLException e) { e.printStackTrace(); }

    System.out.println(DriverManager.drivers().count());
}

Which always results in 1, 0, 0, 1 whenever I compile and run. Where have I gone wrong?

CodePudding user response:

JDBC drivers automatically registered in modern Java

You said:

I was taught to use Class.forName

Your teacher is very much out-of-date.

In modern Java, you no longer need to call Class.forName. JDBC drivers are now automatically loaded via the Java Service Provider Interface (SPI). If curious about how this works, see this Question.

If your JDBC driver fails to be automatically registered, verify its inclusion within your project, or if in a Jakarta EE (Java EE) server, verify the proper location within that environment. You have not posted enough details about your development and deployment scenario for us to diagnose. And verify that you have the right version, which generally should support JDBC 4.x (4.3 is current).

If you continue to have trouble, write a throwaway console app that does nothing but connect to your database. Eliminate as much complexity and distraction as possible.

Regarding the code you show, I have no idea why you would want to be de-registering any drivers. Basically, all of the code you showed in your Question should be unnecessary.

DataSource

Furthermore, usually best to use a DataSource as the way to get connections to your database. A DataSource object holds the information required to connect: server address, port number, username, password, and various proprietary settings specific to your database server product.

I have written a few Answers on Stack Overflow with complete working examples for MySQL, Postgres, & H2. Like this one. I suggest you search for such example from me and the many other fine authors on Stack Overflow.

Here is one such example. The code shown here should be sufficient as the MySQL driver should be automatically loaded.

private DataSource configureDataSource ( )
{
    System.out.println( "INFO - `configureDataSource` method. "   Instant.now() );

    com.mysql.cj.jdbc.MysqlDataSource dataSource = Objects.requireNonNull( new com.mysql.cj.jdbc.MysqlDataSource() );  // Implementation of `DataSource`.
    dataSource.setServerName( "db-mysql-lon2-722-do-user-89973-1.x.db.ondigitalocean.com" );
    dataSource.setPortNumber( 24_090 );
    dataSource.setDatabaseName( "defaultdb" );
    dataSource.setUser( "scott" );
    dataSource.setPassword( "tiger" );
    return dataSource;
}

Usage:

Connection conn = myDataSource.getConnection() ;

Of course you should obtain a DataSource implementation that addresses your needs. For example, some provide fresh new connections while others provide connection pooling. Some are provided by the vendor of your database, and some are third-party.

CodePudding user response:

Since Java 6 (assuming a JDBC 4.0 or higher driver on the initial classpath), JDBC drivers are loaded automatically. This means that the driver was loaded automatically the moment DriverManager was class loaded and initialized.

The static initializer of the driver class is what registers a driver with the driver manager. This static initializer is run when the class is loaded. As the driver class was already loaded, a subsequent Class.forName returns the already loaded class, and the static initializer does not run again, so nothing is registered with DriverManager.

In other words:

  1. DriverManager is class loaded and loads drivers using ServiceLoader
    • com.mysql.cj.jdbc.Driver is loaded through ServiceLoader and its static initializer registers an instance with DriverManager
  2. You remove all drivers from DriverManager
  3. You call Class.forName("com.mysql.cj.jdbc.Driver")
    • Given the class was already class loaded, Java returns the already loaded class
    • Nothing is registered as the static intializer doesn't run again
  4. You manually register an instance with DriverManager (BTW, this is not something you should normally do, DriverManager.registerDriver is for JDBC drivers to call).
  • Related