Expert · JDBC, Maven, Gradle and JUnit · topic 46 of 60 · 30 min
JDBC: talking to a database
Explanation
Why JDBC?
Almost every business application stores data in a relational database such as PostgreSQL, MySQL or Oracle. JDBC is the low-level standard API all Java database tools build on, including JPA and Spring Data (module 11). Each database provides a driver (a JAR) that implements JDBC for it.
Connecting and querying
import java.sql.*;
String url = "jdbc:postgresql://localhost:5432/shop"; // MySQL: jdbc:mysql://localhost:3306/shop
String user = System.getenv("DB_USER"); // never hard-code credentials
String pass = System.getenv("DB_PASSWORD");
String sql = "SELECT id, name, city FROM customers WHERE city = ? ORDER BY name";
try (Connection conn = DriverManager.getConnection(url, user, pass);
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, "Pune"); // fill the first ? (1-based)
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) { // move to the next row
System.out.println(rs.getInt("id") + " " + rs.getString("name"));
}
}
} catch (SQLException e) {
System.out.println("Database error: " + e.getMessage());
}executeQuery is for SELECT and returns a ResultSet. executeUpdate is for INSERT, UPDATE and DELETE and returns the number of rows changed. Parameter positions start at 1, not 0.
String insert = "INSERT INTO orders (customer_id, amount, status) VALUES (?, ?, ?)";
try (PreparedStatement ps = conn.prepareStatement(insert)) {
ps.setInt(1, 1);
ps.setLong(2, 49_900);
ps.setString(3, "PAID");
int rows = ps.executeUpdate(); // 1
}Transactions
A transaction groups several statements so they all succeed or all fail. Moving money must debit one account AND credit another; if the credit fails, the debit must be undone. By default each statement commits on its own (auto-commit). Turn it off, commit at the end, and roll back on error.
conn.setAutoCommit(false);
try (PreparedStatement debit = conn.prepareStatement("UPDATE accounts SET balance = balance - ? WHERE id = ? AND balance >= ?");
PreparedStatement credit = conn.prepareStatement("UPDATE accounts SET balance = balance + ? WHERE id = ?")) {
debit.setLong(1, amount); debit.setLong(2, fromId); debit.setLong(3, amount);
if (debit.executeUpdate() != 1) throw new SQLException("Insufficient balance");
credit.setLong(1, amount); credit.setLong(2, toId);
credit.executeUpdate();
conn.commit(); // both changes become permanent together
} catch (SQLException e) {
conn.rollback(); // undo everything since the last commit
throw e;
}Connection pools
Opening a database connection takes time (network handshake, authentication). Real applications use a connection pool, which keeps a set of open connections and lends them out. HikariCP is the most common pool and the default in Spring Boot. Code asks the pool (a DataSource) for a connection and "closing" it returns it to the pool.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
JDBC: talking to a database · 1/6
In this lesson you will connect Java to a SQL database with JDBC.
Prefer a video by a teacher? Find free videos on “java jdbc tutorial preparedstatement resultset transaction” on YouTube ↗
In real life: Loading a customer's orders
An order-history screen in a shopping app runs one parameterised query that joins customers and orders for the logged-in user and maps each row into a Java record.
record OrderRow(int id, long amount, String status) {}
List<OrderRow> orders = new ArrayList<>();
String sql = "SELECT id, amount, status FROM orders WHERE customer_id = ? ORDER BY id DESC";
try (Connection c = dataSource.getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {
ps.setInt(1, customerId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) orders.add(new OrderRow(rs.getInt("id"), rs.getLong("amount"), rs.getString("status")));
}
}Practice (0/3 done)
The query a Java app would send through JDBC: list the names of customers from Pune, sorted by name.
Show each customer's name with the total amount of their PAID orders, only for customers who have paid orders, highest total first. (A Java report screen would run this with JDBC.)
Which JDBC method runs an UPDATE statement and returns the number of changed rows?
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- SQL injection and safe queriesJDBC, Maven, Gradle and JUnit · same module
- Maven: building and dependenciesJDBC, Maven, Gradle and JUnit · same module
- Gradle in briefJDBC, Maven, Gradle and JUnit · same module
- Databases with database/sqlGo Programming (backend and cloud) · Building a REST API with a database
- Transactions: all or nothingSQL and Databases · Changing data, transactions and ACID
- Transactions and ACIDBackend Development · SQL in depth
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
In ps.setString(1, "Pune"), what does 1 mean?
Answer: The first ? placeholder (parameters are 1-based)
JDBC parameter indexes start at 1.
What does rs.next() do?
Answer: Moves to the next row and returns false when there are no more
Loop while rs.next() is true.
Why use a transaction for a money transfer?
Answer: So the debit and credit succeed or fail together
Atomicity: all or nothing.
What is HikariCP?
Answer: A JDBC connection pool
It is the default pool in Spring Boot.
What happens if you forget rows.Close()?Related
Answer: Connections leak and the pool can run out, making requests hang
Open Rows hold a connection.
Inside a transaction you run SAVEPOINT s1, then an UPDATE, then ROLLBACK TO s1. What happens?Related
Answer: Only the work after s1 is undone, and the transaction stays open
ROLLBACK TO undoes back to the marker and keeps the earlier work pending.
Why should you not send an SMS from inside an open transaction?Related
Answer: The slow call keeps locks held and makes other users wait; and the SMS cannot be rolled back
Transactions should be short. Outside calls are slow, and an SMS already sent cannot be undone by ROLLBACK.
What is the main fix for SQL injection in Java?Related
Answer: PreparedStatement with parameters
Parameters are the correct default.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 4 more topics in “JDBC, Maven, Gradle and JUnit” before its exam: SQL injection and safe queries, Maven: building and dependencies, Gradle in brief, Unit testing with JUnit.
- Module 10 exam: JDBC, Maven, Gradle and JUnit · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Spring Boot basics. 60 topics left in the course before the final exam.