By WebNest Studio Engineering Team
Advanced Java Tutorial
Connecting to a Database with DriverManager
DriverManager is the entry point for obtaining a JDBC Connection. You give it a JDBC URL (which identifies the database type, host, port, and database name) along with credentials, and it returns a live connection backed by whichever registered driver claims to understand that URL.
The JDBC URL Format
A JDBC URL always starts with jdbc:, followed by a subprotocol identifying the database vendor, followed by vendor-specific connection details. The general shape is jdbc:<subprotocol>://<host>:<port>/<database>?<properties>.
- MySQL:
jdbc:mysql://localhost:3306/store?useSSL=false&serverTimezone=UTC - PostgreSQL:
jdbc:postgresql://localhost:5432/inventory - Oracle:
jdbc:oracle:thin:@localhost:1521:orcl - SQL Server:
jdbc:sqlserver://localhost:1433;databaseName=Sales - H2 in memory (no server needed, handy for learning and tests):
jdbc:h2:mem:inventory
Getting the Driver onto the Classpath
DriverManager is part of the JDK, but the drivers are not. Each database vendor ships its driver as a jar: org.postgresql:postgresql, com.mysql:mysql-connector-j, com.h2database:h2 and so on. Add it as a Maven or Gradle dependency, or pass it with -cp when running from the command line. Since JDBC 4.0 (Java 6) every driver jar registers itself through the ServiceLoader mechanism, so the old Class.forName("org.postgresql.Driver") line you still see in many tutorials is no longer needed. You can check which drivers were found with DriverManager.drivers(): with the H2 jar on the classpath it lists org.h2.Driver, and without it the list is empty.
Obtaining a Connection
DriverManager.getConnection(url, user, password) asks each registered driver, in turn, whether it accepts the given URL; the first driver that says yes opens a physical network connection to the database and wraps it as a Connection object. This call is relatively expensive — it typically involves a TCP handshake, authentication, and session setup on the server — which is one reason applications avoid opening a fresh connection for every single query (see connection pooling). If no registered driver accepts the URL, you get SQLException: No suitable driver found for .... That message means either the driver jar is missing from the classpath or the URL is misspelled; it never means the database is down.
Reading Connection Errors
Every SQLException carries more than a message. getSQLState() returns a five-character code defined by the SQL standard, and getErrorCode() a vendor-specific number. The first two characters of the SQLState tell you the category, which is the same across databases and therefore safe to check in code:
08xxx: connection problems, such as a server that cannot be reached or a URL no driver accepts (08001).28xxx: authentication failed, for example a wrong user name or password (28000).42xxx: syntax errors or unknown tables and columns, which you will meet once queries start running.
Always Use try-with-resources
Connection, along with Statement and ResultSet, implements AutoCloseable. Wrapping them in a try-with-resources statement guarantees they are closed — releasing the underlying socket and any server-side session resources — even if an exception is thrown while the query runs. Relying on manually calling close() in a finally block is more verbose and easier to get wrong (for example, forgetting to close a ResultSet before its Statement).
Keeping Credentials out of the Code
A password written into a .java file ends up in version control, in every copy of the repository and in the compiled class. Read connection details from the environment instead, for example System.getenv("DB_URL"), or from a properties file that is not committed. In frameworks such as Spring Boot this is handled for you through spring.datasource.* properties, and the framework uses a connection pool rather than DriverManager directly.
Examples
Opening and safely closing a connection with try-with-resources (run with the H2 2.4.240 jar: java -cp h2.jar ConnectDemo.java)
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectDemo {
// For PostgreSQL: "jdbc:postgresql://localhost:5432/inventory" plus the postgresql jar
private static final String URL = "jdbc:h2:mem:inventory";
private static final String USER = "sa";
private static final String PASSWORD = "";
public static void main(String[] args) {
try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD)) {
DatabaseMetaData meta = conn.getMetaData();
System.out.println("Connected to: " + meta.getDatabaseProductName()
+ " " + meta.getDatabaseProductVersion());
System.out.println("Driver: " + meta.getDriverName() + " " + meta.getDriverVersion());
System.out.println("Catalog: " + conn.getCatalog());
System.out.println("Auto-commit enabled: " + conn.getAutoCommit());
System.out.println("Valid: " + conn.isValid(2)); // pings, waits at most 2 s
} catch (SQLException e) {
System.out.println("Connection failed: " + e.getMessage());
}
// conn.close() is called automatically here, even on exception
}
}
Connected to: H2 2.4.240 (2025-09-22)
Driver: H2 JDBC Driver 2.4.240 (2025-09-22)
Catalog: INVENTORY
Auto-commit enabled: true
Valid: true
What the two most common connection errors look like
// 1. A typo in the subprotocol (h3 instead of h2)
try (Connection conn = DriverManager.getConnection("jdbc:h3:mem:inventory", "sa", "")) {
System.out.println("connected?");
} catch (SQLException e) {
System.out.println("Typo: " + e.getMessage() + " (SQLState " + e.getSQLState() + ")");
}
// 2. A wrong password for a database that exists
try (Connection c1 = DriverManager.getConnection("jdbc:h2:mem:shop;DB_CLOSE_DELAY=-1", "admin", "right");
Connection c2 = DriverManager.getConnection("jdbc:h2:mem:shop", "admin", "wrong")) {
System.out.println("connected?");
} catch (SQLException e) {
System.out.println("Wrong password: " + e.getMessage()
+ " (SQLState " + e.getSQLState() + ")");
}
Typo: No suitable driver found for jdbc:h3:mem:inventory (SQLState 08001)
Wrong password: Wrong user name or password [28000-240] (SQLState 28000)
Common Mistakes
- Hardcoding the JDBC URL, username, and password directly in source code instead of externalizing them into configuration.
- Mistyping the JDBC URL subprotocol (e.g. "jdbc:mysqll://...") and getting a confusing "No suitable driver" error instead of a clear typo message.
- Not closing connections (or not using try-with-resources), which exhausts the database's max_connections limit under load.
- Assuming getConnection() is cheap enough to call once per query in a hot path — it is not, which is why pooling exists.
- Forgetting to add the driver jar as a dependency, then searching for a database problem when the error says "No suitable driver".
- Matching on exception message text, which differs between databases and driver versions, instead of on getSQLState().
Exercise
A teammate is about to make this mistake: Hardcoding the JDBC URL, username, and password directly in source code instead of externalizing them into configuration. Use The JDBC URL Format to review the decision. Write a corrected implementation or design sketch that follows JDBC URLs follow the pattern jdbc:<subprotocol>://host:port/database, with vendor-specific details after that., then name one edge case you would check.
Show hints
- Start with The JDBC URL Format and compare your approach with Opening and safely closing a connection with try-with-resources (run with the H2 2.4.240 jar: java -cp h2.jar ConnectDemo.java). Identify the decision or behavior the lesson recommends.
- Walk through your scenario step by step. Confirm that it follows JDBC URLs follow the pattern jdbc:<subprotocol>://host:port/database, with vendor-specific details after that. and that it would catch the failure described by Hardcoding the JDBC URL, username, and password directly in source code instead of externalizing them into configuration..
Quick quiz
1. Which choice best describes the recommended approach in Connecting to a Database with DriverManager?
- A. Hardcoding the JDBC URL, username, and password directly in source code instead of externalizing them into configuration.
- B. Mistyping the JDBC URL subprotocol (e.g. "jdbc:mysqll://...") and getting a confusing "No suitable driver" error instead of a clear typo message.
- C. JDBC URLs follow the pattern jdbc:<subprotocol>://host:port/database, with vendor-specific details after that.
Show answer
C. This is the recommended approach: JDBC URLs follow the pattern jdbc:<subprotocol>://host:port/database, with vendor-specific details after that. Avoid: Hardcoding the JDBC URL, username, and password directly in source code instead of externalizing them into configuration.
Interview questions
Why does this principle matter in Connecting to a Database with DriverManager: JDBC URLs follow the pattern jdbc:<subprotocol>://host:port/database, with vendor-specific details after that.
Show answer
JDBC URLs follow the pattern jdbc:<subprotocol>://host:port/database, with vendor-specific details after that. Apply this in The JDBC URL Format; the example Opening and safely closing a connection with try-with-resources (run with the H2 2.4.240 jar: java -cp h2.jar ConnectDemo.java) shows one way to do it. Avoid Hardcoding the JDBC URL, username, and password directly in source code instead of externalizing them into configuration. and explain how your implementation or design prevents that failure.
Key Points to Remember
- JDBC URLs follow the pattern jdbc:<subprotocol>://host:port/database, with vendor-specific details after that.
- Driver jars register themselves automatically (JDBC 4.0+); Class.forName() is no longer required.
- DriverManager.getConnection(url, user, password) opens a real network connection and returns a Connection object.
- "No suitable driver" means a missing driver jar or a misspelled URL; SQLState 08xxx is a connection problem and 28xxx a login problem.
- Connection, Statement, and ResultSet are AutoCloseable — always manage them with try-with-resources.
- Opening a raw connection is relatively expensive, which motivates connection pooling in real applications.
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
These examples need a JDK project with their libraries on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering