Java JDBC Drivers
JDBC driver types, loading drivers in modern Java, and using DriverManager and DataSource to obtain connections.
A JDBC driver is the vendor-supplied library that turns generic java.sql calls into the specific network protocol a database understands. The JDBC API is part of the JDK; the driver is an external JAR you add to the classpath. No driver, no connection.
This chapter covers the four driver types (and why only one matters today), how modern Java auto-loads drivers without Class.forName, the difference between DriverManager and DataSource, and how DriverManager decides which driver handles a given URL. For the bigger picture of how the JDBC API fits together, see Java JDBC Introduction; to act on a live connection once you have one, see Java JDBC Connection.
The four driver types
The JDBC spec defines four historical driver types. In modern practice you almost always use Type 4:
| Type | Name | Notes |
|---|---|---|
| 1 | JDBC-ODBC bridge | Obsolete; removed from the JDK in Java 8 |
| 2 | Native-API | Wraps a C client library; needs native code installed |
| 3 | Network protocol | Talks to middleware that talks to the database |
| 4 | Pure-Java (thin) | A single JAR, all Java, talks the DB wire protocol directly |
Type 4 drivers — org.postgresql.Driver, com.mysql.cj.jdbc.Driver, the H2 driver — are just a JAR on the classpath. That is what you add to pom.xml or build.gradle. Because they are pure Java, they run on any platform the JVM does, with nothing to install on the host machine. Treat the older types as historical: you will see them in old docs and exam questions, but you will not reach for them in new code.
Loading a driver: you usually do nothing
Old tutorials show Class.forName("com.mysql.cj.jdbc.Driver"). Since JDBC 4.0 (Java 6) that line is unnecessary. Drivers ship a META-INF/services/java.sql.Driver file, and DriverManager auto-registers them via the ServiceLoader mechanism the first time you call getConnection. So the modern code is simply:
// No Class.forName needed — the driver JAR self-registers.
Connection conn = DriverManager.getConnection(
"jdbc:postgresql://localhost:5432/shop", "app", "secret");DriverManager vs. DataSource
Two ways to obtain a connection:
DriverManager.getConnection(url, user, password)— simplest; good for tools, scripts, and demos. Opens a brand-new physical connection each call.DataSource— the preferred approach for applications and servers. ADataSource(usually backed by a connection pool like HikariCP) hands out pooled connections, soclose()returns the connection to the pool instead of tearing down a socket.
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:postgresql://localhost:5432/shop");
ds.setUsername("app");
ds.setPassword("secret");
try (Connection conn = ds.getConnection()) { /* borrowed from the pool */ }The JDBC URL
Every connection starts with a JDBC URL, which always has the shape jdbc:<subprotocol>:<subname>:
jdbc:postgresql://localhost:5432/shop
│ │ │
│ │ └─ subname: host, port, database, options
│ └───────────── subprotocol: identifies the vendor/driver
└────────────────── scheme: always "jdbc"The subprotocol (postgresql, mysql, h2, oracle, sqlserver) is the part that decides which driver handles the request. Each vendor documents its own URL format and the options that follow the database name (TLS settings, time zone, connection flags), so check the driver's docs for the exact syntax.
How DriverManager picks a driver
When you call getConnection, DriverManager walks its list of registered drivers and asks each one "do you recognise this URL?" via Driver.acceptsURL. The first that says yes is used; if none do, you get No suitable driver found. A driver typically answers "yes" only when the URL's subprotocol matches its own — which is why the subprotocol, not the host, is what routes the request.
A worked example: inspecting the driver registry
This program lists the drivers DriverManager knows about, then asks it to connect to three different vendor URLs — letting you watch the URL-matching contract in action.
What to take from the run:
DriverManager.getDrivers()returns the registered drivers as anEnumeration. On a runtime with no driver JARs the list is empty — addpostgresql.jarto the classpath and the PostgreSQLDriverwould appear here automatically, with noClass.forNamecall.- The URL's subprotocol (the part after
jdbc:—postgresql,mysql,h2) is what each driver matches on. That is how onegetConnectioncall routes to the right vendor: the driver claims its own subprotocol. - Every URL failed the same way here because no driver is present. In a real deployment, exactly one driver would claim each URL; if you forget the dependency you see precisely this "No suitable driver found" message — a missing-JAR symptom, not a bad-password one.
- Registration is automatic via
ServiceLoader, but the driver JAR must still be on the classpath. The lesson: a "No suitable driver" error is a build/dependency problem, fixed inpom.xml, not in your Java code. DriverexposesgetMajorVersion/getMinorVersion, so you can log exactly which driver build is running — useful when a bug depends on the driver version, not your code.
Once a driver is on the classpath and getConnection returns a live Connection, the next step is running SQL through it — see Java JDBC Connection and Java JDBC Statement.