If you cannot connect your Java code to a database, your application is just a fancy calculator that forgets everything when the power goes off. JDBC is the standard bridge that lets Java programmes talk to any relational database — Oracle, MySQL, PostgreSQL, or SQL Server — using a single, consistent set of commands. For the 1Z0-829 exam, understanding JDBC is non-negotiable because roughly 10% of the questions will test your ability to connect, query, and process results correctly.
Jump to a section
A simple way to picture JDBC Database Access
A head chef runs a busy restaurant kitchen. Every dinner service, the chef receives a stack of paper orders from the waitstaff. Each order is a request for specific dishes — a steak, a salad, a dessert. The chef must read each order, grab the correct ingredients from the walk-in fridge, and prepare the meal exactly as written. If the order is poorly written or missing an item, the chef sends it back. Once the meal is ready, the chef hands the plate to the waitstaff to deliver to the customer.
In this scene, the chef is your Java application. The paper orders are SQL queries — structured requests for data. The walk-in fridge is the database itself, full of tables of information. The waitstaff are the JDBC driver that carries the order to and from the database. A carefully written order lets the chef work quickly and correctly. A messy order causes confusion or, worse, a wrong meal.
Now imagine that a popular appetiser runs out mid-service. The chef does not rewrite every order. Instead, the chef tells the waitstaff, "For all future orders, replace clam chowder with French onion soup." That is PreparedStatement — a reusable, pre-compiled order template that only changes the data, not the structure. It prevents mix-ups (SQL injection attacks) and is much faster than handwriting each order from scratch.
JDBC stands for Java Database Connectivity. It is a set of interfaces and classes in the java.sql package that allows a Java program to send SQL statements to a database and receive results back. Think of it as a universal translator: your Java code speaks JDBC, and the database vendor provides a JDBC driver (like a language pack) that translates JDBC calls into the database's native protocol.
To use JDBC, you first need a database installed and running. For the exam, you do not need to install anything — you just need to understand the code patterns. The essential steps are always: 1) Load the driver (though modern JDBC 4.0+ does this automatically if the driver JAR is on the classpath). 2) Establish a connection using DriverManager.getConnection(url, username, password). The URL looks like jdbc:vendor://host:port/databaseName — for example, jdbc:mysql://localhost:3306/mydb. 3) Create a statement object. There are three types: Statement, PreparedStatement, and CallableStatement. 4) Execute the query using methods like executeQuery() for SELECT, executeUpdate() for INSERT/UPDATE/DELETE, or execute() for any SQL. 5) Process the results, typically by looping through a ResultSet. 6) Close all resources (Connection, Statement, ResultSet) to avoid memory leaks.
A Statement is the simplest — you pass a complete SQL string to it. But this is dangerous because if that string includes user input, a malicious user could inject SQL commands. For example, a login form where the username field is ' OR 1=1 -- would trick Statement into returning all users. PreparedStatement prevents this by separating the SQL structure from the data. You write the SQL with question marks as placeholders, then call setString(1, userInput) to safely bind the user's value. The database compiles the PreparedStatement once and reuses it for every execution, which is also faster for repeated queries.
CallableStatement is used for calling stored procedures — pre-written SQL blocks stored inside the database. You write {call procedureName(?, ?)} and use registerOutParameter() to get output values. Processing results requires a ResultSet, which is a cursor pointing to a table of results. You call rs.next() to move to the first row, then getString("columnName") or getInt(1) to extract column values. The ResultSet is iterable forward-only by default, but can be made scrollable or updatable with extra parameters when creating the Statement.
Resource management is critical. Every Connection, Statement, and ResultSet should be closed in a finally block, or better, using try-with-resources (introduced in Java 7). The try-with-resources syntax automatically closes any resource that implements AutoCloseable when the try block ends. This is the pattern the exam expects you to use — it is clean and prevents resource leaks.
JDBC replaced older, database-specific APIs like ODBC (Open Database Connectivity) for Java programmers. Before JDBC, switching from Oracle to MySQL meant rewriting your data access code from scratch. JDBC makes the database vendor a configurable detail — you change the driver JAR and the URL, and the rest of your code stays the same.
Import JDBC packages
Add import java.sql.*; to your Java file. This gives you access to the core JDBC classes: Connection, Statement, PreparedStatement, ResultSet, and DriverManager.
Load and register the JDBC driver
In modern JDBC (4.0+), this happens automatically when you add the vendor's JAR to your classpath. But you still need to have that JAR available — for example, postgresql-42.x.x.jar for PostgreSQL.
Establish a connection
Call DriverManager.getConnection(url, username, password). The URL is a string like jdbc:postgresql://localhost:5432/mydb. This step creates a live link between your Java programme and the database server.
Create a statement object
From the Connection object, create a PreparedStatement (preferred) using connection.prepareStatement("SELECT * FROM users WHERE id = ?"). The ? is a parameter placeholder that you fill in safely later.
Set parameter values and execute the query
Use methods like setString(1, "Smith") to fill in placeholders. Then call executeQuery() for SELECT or executeUpdate() for INSERT/UPDATE/DELETE. The database executes the SQL and returns results.
Process the ResultSet
If you executed a query, you get a ResultSet. Loop through it with while(rs.next()), and extract column values using getString("columnName") or getInt("columnName"). Each call to next() moves the cursor to the next row.
Close resources
Always close ResultSet, Statement, and Connection in that order (reverse of creation). Using try-with-resources does this automatically when the try block exits, even if an exception occurs.
An IT professional working at a healthcare software company needs to build a feature that lets doctors search patient records by surname. The developer starts by writing a Java method called findPatientsByLastName(String lastName). Inside this method, the developer creates a Connection to the PostgreSQL database that stores patient data. The connection URL includes the database server's IP address, the port (usually 5432 for PostgreSQL), the database name 'hospitals_db', and a user account with read-only permissions.
Next, the developer writes a PreparedStatement: "SELECT * FROM patients WHERE last_name = ?". Notice the question mark — this is the placeholder for the doctor's search input. The developer then calls preparedStatement.setString(1, lastName) to safely insert the doctor's search term. This prevents a scenario where a doctor types "Smith' OR 1=1 --" into the search box and accidentally (or maliciously) retrieves every patient record.
The developer then calls executeQuery() and gets back a ResultSet. The code loops through the ResultSet with while(rs.next()), extracting each patient's ID, first name, last name, date of birth, and NHS number using rs.getInt("patient_id") and rs.getString("first_name"). Each row is added to a List<Patient> object. After the loop, the developer must close the ResultSet, PreparedStatement, and Connection. Modern Java code uses try-with-resources to handle this automatically.
For batch operations — like importing thousands of lab results from a CSV file — the developer uses PreparedStatement.addBatch() and executeBatch(). This sends all the SQL statements in one network trip instead of one at a time, making the import ten times faster. The developer also uses transactions to ensure that if any one insert fails, the entire batch is rolled back so the database is not left with partial data. This is done by calling connection.setAutoCommit(false), running the batch, then calling connection.commit() or connection.rollback() on error.
Finally, the developer writes unit tests using an in-memory database like H2 to verify the query logic without touching the real hospital database. This is a common development practice: test with a lightweight database that behaves just like PostgreSQL but runs in process and resets between test runs.
The 1Z0-829 exam tests JDBC with about 5–8 questions. They focus heavily on the differences between Statement, PreparedStatement, and CallableStatement. Expect at least one question that presents a code snippet using Statement with concatenated user input and asks you to identify the security risk (SQL injection). The correct answer is always to use PreparedStatement with placeholder parameters.
Another frequent question type: given a ResultSet, which method correctly retrieves a column value? They will test the difference between rs.getInt(1) — which uses column index — and rs.getInt("column_name") — which uses column label. They may give you a column name that is spelled slightly differently in the SQL alias (e.g., SELECT first_name AS name FROM patients) and ask which getter will work. The trap is that getString("first_name") would fail because the output column is named "name". You must use the alias, not the original column.
Resource closing is a favourite trap. The exam will show code that closes only the Connection or only the Statement, and ask what goes wrong. The correct answer pattern: all three may need closing, and try-with-resources is the safest approach. They also test that the order of closing does not matter if you use try-with-resources, but if you close manually, close ResultSet first, then Statement, then Connection. - Always use PreparedStatement for queries with user input (SQL injection prevention is a key exam objective). - CallableStatement uses {call procedureName(?, ?)} syntax, not SQL strings. - executeQuery() returns a ResultSet; executeUpdate() returns an int (number of rows affected); execute() returns a boolean (true if ResultSet, false if update count). - Connections must be closed in the reverse order of creation when doing it manually. - Never catch an SQLException silently — the exam expects you to either handle it or declare it in the method signature.
JDBC is a standard Java API that lets your code talk to any relational database without changing your application logic.
Always use PreparedStatement instead of Statement when your SQL includes user-supplied values to prevent SQL injection attacks.
Use try-with-resources to automatically close Connection, Statement, and ResultSet objects to avoid resource leaks.
The executeQuery() method is for SELECT statements and returns a ResultSet; executeUpdate() is for INSERT, UPDATE, DELETE and returns a row count.
A ResultSet cursor starts before the first row — you must call next() to move to the first row before reading data.
CallableStatement is used to call stored procedures using {call procName(?, ?)} syntax with registerOutParameter() for output values.
The JDBC URL format is jdbc:vendor://host:port/databaseName — get the syntax wrong and the connection fails immediately.
These come up on the exam all the time. Here's how to tell them apart.
Statement
Used for static SQL that never changes
Vulnerable to SQL injection if concatenating user input
Database compiles the SQL every time it is executed
PreparedStatement
Used for SQL with variable parameters (placeholders)
Safe against SQL injection — input is always treated as data
Database compiles once; re-executes with different parameters quickly
executeQuery()
Used only for SELECT statements
Returns a ResultSet object containing rows of data
Cannot return the number of rows affected
executeUpdate()
Used for INSERT, UPDATE, DELETE, and DDL statements
Returns an int — the number of rows changed
Does not return a ResultSet
ResultSet
A database cursor — holds a reference to live database data
Must be closed to free database resources
Iterated forward-only by default (unless scrollable)
List of Objects
An in-memory Java collection — data is copied out of the database
Does not need closing — garbage collected
Can be indexed and sorted arbitrarily
Manual resource closing
Requires finally block with null checks
Easy to forget a resource, causing leaks
Must close in reverse order: ResultSet, Statement, Connection
try-with-resources
Resources declared in try() are auto-closed in reverse order
No finally block needed — cleaner code
Introduced in Java 7; preferred pattern for modern code
Mistake
JDBC is a database driver that I install on my computer.
Correct
JDBC is a Java API (a set of interfaces). The actual driver is a JAR file provided by the database vendor that implements those interfaces.
The name 'JDBC driver' confuses people into thinking JDBC itself is the driver. In reality, JDBC defines the rules; the driver follows them.
Mistake
I must manually load the JDBC driver with Class.forName() before connecting.
Correct
Since JDBC 4.0 (Java 6), drivers are loaded automatically if the driver JAR is on the classpath. The Class.forName() call is obsolete for modern development.
Many outdated tutorials still show the old way, and beginners copy that code without realising it is unnecessary.
Mistake
Statement and PreparedStatement are interchangeable, so I can just use whichever is shorter.
Correct
They are not interchangeable for security. PreparedStatement prevents SQL injection and is faster for repeated execution. Statement should only be used for static, hardcoded SQL.
Statement syntax looks simpler (no placeholders), so beginners gravitate to it, unaware of the security implications.
Mistake
All JDBC drivers connect to databases the same way, so I only need one driver JAR.
Correct
Each database vendor provides its own driver (e.g., com.mysql.cj.jdbc.Driver for MySQL, org.postgresql.Driver for PostgreSQL). You need the correct driver for the database you are connecting to.
JDBC's abstraction makes it feel like one solution fits all, but the underlying network protocols are different.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
executeQuery() is for SELECT statements and returns a ResultSet. executeUpdate() is for INSERT, UPDATE, DELETE statements and returns an int (number of rows affected). execute() is for any SQL and returns a boolean — true if the result is a ResultSet, false if it is an update count.
No. You can use an in-memory database like H2, which runs inside your Java application and does not require installation. For the exam itself, you only need to understand code patterns — not actually run code.
Remember that the ResultSet cursor starts before the first row. You must call rs.next() once to move to the first row. If you skip next(), you will read nothing.
SQL injection is when an attacker types malicious SQL into a text field, e.g., ' OR 1=1 --. PreparedStatement treats the user input as data only, not executable SQL code, so it is safe.
Yes. That is one of the main benefits. You can call setString(1, newValue) and executeQuery() again without recompiling the SQL. This is more efficient than creating a new Statement each time.
The connection stays open and consumes database resources. Eventually, the database may run out of available connections, causing the application to fail. That is why try-with-resources is essential.
You've finished JDBC Database Access. Continue through the 1Z0-829 study guide to build a complete picture of the exam.
Done with this chapter?