JDBC
JDBC (Java Database Connectivity) is the standard Java API that lets your programs talk to relational databases — MySQL, PostgreSQL, Oracle, SQLite, and more — using plain SQL. With just a handful of classes and interfaces, you can open a connection, run queries, and process results without locking yourself into any particular database vendor.
What Is JDBC?
Introduced in Java 1.1 and refined ever since, JDBC lives in the java.sql and javax.sql packages. It acts as a bridge between your Java code and a database driver (a vendor-supplied library). You write standard JDBC calls; the driver translates them into the wire protocol your database understands.
Your Java Code
↓
JDBC API (java.sql)
↓
JDBC Driver (vendor JAR)
↓
Database (MySQL, PostgreSQL, …)
This layered design means switching databases usually requires nothing more than swapping the driver JAR and changing the connection URL — your application logic stays untouched.
A Minimal JDBC Example
Here is the smallest possible working program: connect to a database, run a query, and print every row.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JdbcDemo {
public static void main(String[] args) throws Exception {
String url = "jdbc:mysql://localhost:3306/mydb";
String user = "root";
String pass = "secret";
try (Connection conn = DriverManager.getConnection(url, user, pass);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id, name FROM users")) {
while (rs.next()) {
System.out.println(rs.getInt("id") + " — " + rs.getString("name"));
}
}
}
}
Output:
1 — Alice
2 — Bob
3 — Carol
Note: The try-with-resources block automatically closes
ResultSet,Statement, andConnectionin reverse order when the block exits — even if an exception is thrown. Always use this pattern to avoid connection leaks.
Core JDBC Interfaces at a Glance
| Interface / Class | Role |
|---|---|
DriverManager | Bootstraps connections using a URL |
Connection | Represents one live session with the database |
Statement | Executes static SQL strings |
PreparedStatement | Pre-compiled, parameterised SQL |
CallableStatement | Calls stored procedures |
ResultSet | Cursor over the rows returned by a query |
ResultSetMetaData | Describes column names, types, and counts |
DatabaseMetaData | Describes the database itself (tables, indexes, …) |
How It Works Under the Hood
When you call DriverManager.getConnection(url, ...), JDBC scans all registered Driver implementations (loaded via ServiceLoader from META-INF/services/java.sql.Driver inside the driver JAR since JDBC 4.0) and asks each one “do you understand this URL?” The first driver that says yes creates a Connection backed by a real TCP socket (or shared memory pipe) to the database server.
Every SQL string you send travels over that socket. The database parses it, plans it, and returns results as a network stream. ResultSet.next() fetches rows from that stream, often buffering a chunk at a time (the fetch size — tunable with stmt.setFetchSize(n)).
Tip: In production, never open a raw
DriverManagerconnection per request. Use a connection pool (HikariCP, c3p0, or the one bundled in your app server) so sockets are reused across requests, dramatically reducing latency.
JDBC Versions at a Glance
| JDBC Version | Java Version | Key Addition |
|---|---|---|
| JDBC 1.0 | Java 1.1 | Core API |
| JDBC 2.0 | Java 1.2 | Scrollable ResultSet, batch updates |
| JDBC 3.0 | Java 1.4 | Savepoints, ParameterMetaData |
| JDBC 4.0 | Java 6 | Auto-loading drivers, java.sql.SQLXML |
| JDBC 4.1 | Java 7 | try-with-resources support |
| JDBC 4.2 | Java 8 | java.time types, large update counts |
| JDBC 4.3 | Java 9 | ShardingKey, Connection.beginRequest() |
Modern Java (21) ships with JDBC 4.3. You get full java.time integration — pass a LocalDate directly to PreparedStatement.setObject() instead of converting to java.sql.Date.
Security: Always Use PreparedStatement
Never concatenate user input directly into a SQL string — that opens the door to SQL injection attacks.
// DANGEROUS — never do this
String sql = "SELECT * FROM users WHERE name = '" + userInput + "'";
// SAFE — always do this
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM users WHERE name = ?");
ps.setString(1, userInput);
ResultSet rs = ps.executeQuery();
PreparedStatement sends the SQL template to the database once; the driver then sends only the parameter values. The database never re-parses the template with user data, so injection is impossible by design.
Warning: Even
LIKEpatterns need care — a%in user input still matches everything. Escape wildcard characters before binding them as parameters.
Transactions in Brief
By default, JDBC runs in auto-commit mode: every statement is its own transaction. For multi-step operations you need explicit transactions:
conn.setAutoCommit(false);
try {
stmt.executeUpdate("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
stmt.executeUpdate("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
conn.commit();
} catch (SQLException e) {
conn.rollback();
throw e;
}
See Transaction Management for savepoints, isolation levels, and best practices.
In This Section
- JDBC Drivers — Learn the four types of JDBC drivers and how to choose the right one for your database.
- Steps to Connect a Database — Walk through every step from loading the driver to closing the connection, with full working code.
- Connecting to MySQL — Set up a MySQL connection from scratch, including the dependency, URL format, and common pitfalls.
- DriverManager — Understand how
DriverManagerdiscovers and manages drivers, and when to useDataSourceinstead. - Connection Interface — Explore all the things a
Connectionobject can do: transactions, savepoints, metadata, and more. - Statement — Execute static SQL queries and updates, and learn when
Statementis appropriate versusPreparedStatement. - PreparedStatement — Use parameterised queries for safety and performance — the right tool for almost every SQL operation.
- CallableStatement — Call database stored procedures and functions, and retrieve IN/OUT parameters.
- ResultSet — Navigate rows, read typed column values, and work with scrollable and updatable result sets.
- ResultSetMetaData — Inspect column names, data types, and nullability at runtime — useful for generic query tools.
- DatabaseMetaData — Query the database itself: list tables, columns, indexes, supported features, and SQL dialects.
- Transaction Management — Master commit, rollback, savepoints, and isolation levels to keep your data consistent.
- Batch Processing — Send many INSERT or UPDATE statements as a single round-trip to dramatically improve bulk-write throughput.
- RowSet — Use the disconnected, serialisable
RowSetinterfaces (CachedRowSet,JdbcRowSet) for flexible data handling.
Related Topics
- Serialization — Persist Java objects to disk or send them over the network, often paired with JDBC for offline data handling.
- Exception Handling — JDBC methods throw checked
SQLException; solid exception handling is essential in database code. - PreparedStatement — The single most important JDBC class — go here after the overview.
- Collections Framework — You will typically collect JDBC results into
List,Map, or custom POJOs. - Stream API — Process rows fetched from JDBC as Java streams for clean, functional-style data transformation.
- Design Patterns — DAO (Data Access Object) and Repository patterns keep your JDBC code organised and testable.