Database Access (JDBC)
JDBC (Java Database Connectivity) is the standard Java API for connecting to and interacting with relational databases. It defines a common set of interfaces — Connection, Statement, ResultSet, and friends — that every database vendor implements with its own driver, so the same Java code can talk to MySQL, PostgreSQL, Oracle, or SQL Server just by swapping the driver and connection URL.
Opening a connection
DriverManager.getConnection() takes a JDBC URL (which encodes the database vendor, host, port, and database name) plus credentials, and returns a Connection — the live link to the database that every subsequent query flows through.
Opening a JDBC connection
String url = "jdbc:postgresql://localhost:5432/mydb";
String user = "app_user";
String password = "secret";
try (Connection conn = DriverManager.getConnection(url, user, password)) {
System.out.println("Connected: " + !conn.isClosed());
} catch (SQLException e) {
e.printStackTrace();
}Statement vs. PreparedStatement
JDBC offers two ways to run SQL: Statement, which executes a literal SQL string, and PreparedStatement, which executes a parameterized SQL template with ? placeholders filled in separately. They look similar, but the difference matters a great deal once user input is involved.
Statement | PreparedStatement | |
|---|---|---|
SQL construction | String concatenation | Parameterized template with |
SQL injection risk | High if user input is concatenated in | None — parameters are never interpreted as SQL |
Performance (repeated calls) | Re-parsed every execution | Can be pre-compiled and reused by the driver/DB |
Typical use | Fixed, hand-written admin SQL with no external input | Any query involving variable or user-supplied values |
Unsafe: building SQL by concatenation
// DO NOT DO THIS — vulnerable to SQL injection
String username = request.getParameter("username");
String sql = "SELECT * FROM users WHERE username = '" + username + "'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
// if username is: ' OR '1'='1
// the query becomes: SELECT * FROM users WHERE username = '' OR '1'='1'
// ...returning every row in the tableSafe: PreparedStatement with a bound parameter
String sql = "SELECT id, email FROM users WHERE username = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, username); // bound as data, never parsed as SQL
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getInt("id") + " - " + rs.getString("email"));
}
}
}Reading results with ResultSet
A query returns a ResultSet, a cursor positioned before the first row. Call next() to advance one row at a time — it returns false once there are no more rows — and use the typed getters (getInt, getString, getDouble, ...) to read column values, either by 1-based index or by column name.
Iterating a ResultSet
String sql = "SELECT id, name, price FROM products WHERE price > ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setDouble(1, 50.0);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
double price = rs.getDouble("price");
System.out.printf("%d: %s ($%.2f)%n", id, name, price);
}
}
}Inserts, updates, and deletes
Statements that modify data instead of returning rows use executeUpdate(), which returns the number of rows affected.
Inserting a row
String sql = "INSERT INTO products (name, price) VALUES (?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, "Wireless Mouse");
ps.setDouble(2, 24.99);
int rowsInserted = ps.executeUpdate();
System.out.println(rowsInserted + " row(s) inserted");
}try-with-resources, again
Connection, Statement, PreparedStatement, and ResultSet are all AutoCloseable, and every example above opens them in try-with-resources. This matters more with JDBC than almost anywhere else: database connections are a scarce, pooled resource, and a leaked connection can exhaust the pool and take down the rest of the application. Always let try-with-resources close them, even when an exception is thrown mid-query.
JDBC is the standard API for Java-to-relational-database communication; vendors provide drivers implementing it.
DriverManager.getConnection(url, user, password)opens aConnection.PreparedStatementwith?placeholders andsetXxx()binding must be used for any query touching user input — never concatenate SQL strings.ResultSet.next()advances a query cursor row by row; typed getters read column values.executeUpdate()runs INSERT/UPDATE/DELETE and returns the affected row count.Close
Connection/Statement/ResultSetwith try-with-resources to avoid leaking pooled connections.