1. What is JDBC?

JDBC stands for Java Database Connectivity. It is a Java API that lets your Java program talk to a database (MySQL, Oracle, PostgreSQL, etc.) — send SQL queries, get results back, and manipulate data.

Analogy — JDBC is a Phone Call
Think of JDBC like making a phone call:
1. You pick up the phone (load the driver)
2. You dial the number (create a connection)
3. You talk (send SQL queries)
4. You listen (read results from ResultSet)
5. You hang up (close the connection)
The phone system itself is JDBC — it connects you (Java) to the other person (database).

Why Do We Need JDBC?

Your Java application stores data in variables and objects — but when the app closes, all that data is lost. Databases store data permanently. JDBC is the bridge that lets Java save and retrieve data from a database.

2. JDBC Architecture

JDBC sits between your Java code and the database. Here's the flow:

┌─────────────────┐
│  Java Application │
└────────┬────────┘
         │ calls methods like executeQuery()
┌────────▼────────┐
│    JDBC API       │  ← java.sql package (Connection, Statement, ResultSet)
└────────┬────────┘
         │ translates to database-specific protocol
┌────────▼────────┐
│   JDBC Driver     │  ← e.g., MySQL Connector/J, Oracle JDBC driver
└────────┬────────┘
         │ sends actual SQL over the network
┌────────▼────────┐
│    Database       │  ← MySQL, Oracle, PostgreSQL
└─────────────────┘
Key Idea
You write the same Java code no matter which database you use. Only the driver JAR file and the connection URL change. That's the power of JDBC — it is database-independent.

3. Types of JDBC Drivers

TypeNameHow It WorksUsed?
Type 1 JDBC-ODBC Bridge Uses ODBC driver as middleman. Very slow. Removed in Java 8. Never use.
Type 2 Native-API Uses database-specific native libraries (C/C++). Platform-dependent. Rarely used.
Type 3 Network Protocol Talks to a middleware server that then talks to DB. Complex setup. Rare.
Type 4 Thin / Pure Java Directly talks to database using Java sockets. No middleman. Most used. This is what you use.
Exam Alert
Type 4 (Thin / Pure Java) is the most commonly asked. Remember: it is written entirely in Java, needs no native libraries, and communicates directly with the database. MySQL Connector/J is a Type 4 driver.

4. JDBC Setup

Step 1: Get the MySQL Connector/J JAR

Download mysql-connector-j-8.x.x.jar from the MySQL website and add it to your project's classpath (or lib folder).

Step 2: Load the Driver

Class.forName("com.mysql.cj.jdbc.Driver");
Why Class.forName()?
Class.forName() loads the driver class into JVM memory. When the driver class loads, its static block automatically registers itself with DriverManager. Without this, Java doesn't know which driver to use.

Note: In JDBC 4.0+ (Java 6+), the driver auto-loads if the JAR is on classpath. But TCS exams still ask about Class.forName(), so always know it.

Step 3: Connection URL Format

// Format:
jdbc:mysql://hostname:port/database_name

// Example — connecting to "ilpdb" on your own machine:
jdbc:mysql://localhost:3306/ilpdb
PartMeaningExample
jdbc:mysql://Protocol — tells JDBC to use MySQLAlways this for MySQL
localhostHostname — where the DB server runslocalhost or 192.168.1.5
3306Port — MySQL default port3306 (default)
ilpdbDatabase nameYour database name

5. The 7 Steps of JDBC

Exam Alert — ALWAYS ASKED
The 7 steps of JDBC are asked in almost every PRA and Sprint exam. Memorize the order. Know every line of code.
// Step 1: Import the java.sql package
import java.sql.*;

public class JDBCDemo {
    public static void main(String[] args) {
        try {
            // Step 2: Load/Register the driver
            Class.forName("com.mysql.cj.jdbc.Driver");

            // Step 3: Establish the connection
            Connection con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/ilpdb",  // URL
                "root",                                // username
                "password"                              // password
            );

            // Step 4: Create a Statement object
            Statement stmt = con.createStatement();

            // Step 5: Execute the SQL query
            ResultSet rs = stmt.executeQuery("SELECT * FROM employees");

            // Step 6: Process the results
            while (rs.next()) {
                System.out.println(rs.getInt("id") + " - " + rs.getString("name"));
            }

            // Step 7: Close the connection
            rs.close();
            stmt.close();
            con.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
7 Steps — Quick Memorization
I-L-E-C-E-P-C — "I Love Eating Cheese Every Peaceful Christmas"

1. Import → import java.sql.*;
2. Load → Class.forName("...")
3. Establish → DriverManager.getConnection()
4. Create → con.createStatement()
5. Execute → stmt.executeQuery() or stmt.executeUpdate()
6. Process → while(rs.next()) { ... }
7. Close → con.close()

6. Connection

Getting a Connection

Connection con = DriverManager.getConnection(url, username, password);

The Connection object represents a live session with the database. As long as it's open, you can send queries.

Important Connection Methods

MethodWhat It Does
createStatement()Creates a Statement object
prepareStatement(sql)Creates a PreparedStatement with SQL template
prepareCall(sql)Creates a CallableStatement for stored procedures
setAutoCommit(false)Turns off auto-commit for manual transactions
commit()Commits the current transaction
rollback()Rolls back the current transaction
close()Closes the connection and releases resources
isClosed()Returns true if connection is closed

Try-With-Resources (Best Practice)

Always use try-with-resources so connections auto-close even if an exception occurs:

try (Connection con = DriverManager.getConnection(url, user, pass);
     Statement stmt = con.createStatement();
     ResultSet rs = stmt.executeQuery("SELECT * FROM employees")) {

    while (rs.next()) {
        System.out.println(rs.getString("name"));
    }
    // No need to call close() — happens automatically!

} catch (SQLException e) {
    e.printStackTrace();
}
Warning
If you forget to close a connection, you create a resource leak. The database has a limited number of connections — if they're all used up and not returned, new requests will fail. Always close connections.

7. Statement Types

Exam Alert
Statement vs PreparedStatement vs CallableStatement — comparison questions are very common. Know the differences cold.
FeatureStatementPreparedStatementCallableStatement
Used for Simple, one-time SQL Repeated SQL with parameters Stored procedures
SQL Injection Vulnerable Safe (parameterized) Safe
Performance Slower (compiled every time) Faster (pre-compiled) Depends on DB
Parameters None — SQL is a raw string Uses ? placeholders Uses ? for IN/OUT params
Creation con.createStatement() con.prepareStatement(sql) con.prepareCall(sql)
Best for DDL (CREATE, DROP, ALTER) DML (INSERT, UPDATE, SELECT) Calling stored procedures

Statement Example

Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM employees WHERE dept='IT'");

Why Statement is Dangerous

// User enters this as their name: ' OR '1'='1
String userInput = "' OR '1'='1";
String sql = "SELECT * FROM users WHERE name='" + userInput + "'";
// Becomes: SELECT * FROM users WHERE name='' OR '1'='1'
// This returns ALL rows! This is SQL Injection.
stmt.executeQuery(sql);

8. PreparedStatement in Detail

PreparedStatement is the right way to execute SQL with user input. It uses ? placeholders instead of string concatenation.

// Step 1: Write SQL with ? placeholders (no quotes around ?)
String sql = "SELECT * FROM employees WHERE dept = ? AND salary > ?";

// Step 2: Create the PreparedStatement
PreparedStatement pstmt = con.prepareStatement(sql);

// Step 3: Set the parameter values (index starts at 1, not 0!)
pstmt.setString(1, "IT");       // First ? → "IT"
pstmt.setDouble(2, 50000.0);   // Second ? → 50000.0

// Step 4: Execute
ResultSet rs = pstmt.executeQuery();

Common Setter Methods

MethodJava TypeSQL Type
setInt(index, value)intINTEGER
setString(index, value)StringVARCHAR
setDouble(index, value)doubleDOUBLE
setFloat(index, value)floatFLOAT
setLong(index, value)longBIGINT
setDate(index, value)java.sql.DateDATE
setBoolean(index, value)booleanBOOLEAN
Why PreparedStatement Prevents SQL Injection
With PreparedStatement, the SQL structure is compiled first, then the values are plugged in separately. The database treats the values as data only, never as SQL commands.

Even if a user enters ' OR '1'='1, the database sees it as a literal string — not as SQL code. The SQL structure can't be changed after compilation.
Common Mistake
Parameter index starts at 1, not 0! pstmt.setString(1, "value") is correct. pstmt.setString(0, "value") throws an exception.

9. executeQuery() vs executeUpdate() vs execute()

MethodUsed ForReturnsExample SQL
executeQuery() SELECT statements ResultSet SELECT * FROM users
executeUpdate() INSERT, UPDATE, DELETE, DDL int (rows affected) INSERT INTO users VALUES(...)
execute() Any SQL statement boolean (true if ResultSet) Dynamic/unknown SQL type
// executeQuery() — for SELECT
ResultSet rs = stmt.executeQuery("SELECT * FROM employees");

// executeUpdate() — for INSERT/UPDATE/DELETE
int rowsAffected = stmt.executeUpdate("DELETE FROM employees WHERE id=5");
System.out.println(rowsAffected + " row(s) deleted");

// execute() — for any SQL (rarely used in exams)
boolean hasResultSet = stmt.execute("SELECT * FROM employees");
if (hasResultSet) {
    ResultSet rs2 = stmt.getResultSet();
}
Exam Alert
Q: What does executeUpdate() return?
A: An int — the number of rows affected. For DDL statements (CREATE TABLE, etc.), it returns 0.

Q: What does executeQuery() return?
A: A ResultSet object containing the query results.

10. ResultSet

A ResultSet is like a table of results. It has a cursor that starts before the first row. You call next() to move to each row.

ResultSet rs = stmt.executeQuery("SELECT id, name, salary FROM employees");

// Cursor starts BEFORE first row
// rs.next() moves to first row, returns true
// rs.next() moves to second row, returns true
// ... when no more rows, returns false

while (rs.next()) {
    int id = rs.getInt("id");            // by column name
    String name = rs.getString(2);       // by column index (starts at 1!)
    double salary = rs.getDouble("salary");
    System.out.println(id + " | " + name + " | " + salary);
}

ResultSet Navigation Methods

MethodWhat It DoesDefault Available?
next()Move cursor forward one rowYes (always)
previous()Move cursor back one rowOnly if scrollable
first()Move to first rowOnly if scrollable
last()Move to last rowOnly if scrollable
absolute(n)Move to row number nOnly if scrollable
beforeFirst()Move before first rowOnly if scrollable

ResultSet Types

Type ConstantScrollable?Reflects DB Changes?
TYPE_FORWARD_ONLYNo — only next()No
TYPE_SCROLL_INSENSITIVEYesNo — snapshot at query time
TYPE_SCROLL_SENSITIVEYesYes — sees changes made by others

ResultSet Concurrency

Concurrency ConstantMeaning
CONCUR_READ_ONLYCan only read data (default)
CONCUR_UPDATABLECan update data directly through the ResultSet

Creating a Scrollable ResultSet

Statement stmt = con.createStatement(
    ResultSet.TYPE_SCROLL_INSENSITIVE,  // scrollable
    ResultSet.CONCUR_READ_ONLY           // read-only
);
ResultSet rs = stmt.executeQuery("SELECT * FROM employees");

rs.last();                 // jump to last row
System.out.println("Total rows: " + rs.getRow());  // get current row number
rs.beforeFirst();           // go back to start

11. CRUD Operations — Complete Examples

CRUD
Create (INSERT) | Read (SELECT) | Update (UPDATE) | Delete (DELETE)
Every database application revolves around these four operations. All examples use PreparedStatement.

CREATE — INSERT a New Employee

String sql = "INSERT INTO employees (name, dept, salary) VALUES (?, ?, ?)";

try (PreparedStatement pstmt = con.prepareStatement(sql)) {
    pstmt.setString(1, "Darshan");    // name
    pstmt.setString(2, "Engineering"); // dept
    pstmt.setDouble(3, 75000.0);      // salary

    int rows = pstmt.executeUpdate();  // returns number of rows inserted
    System.out.println(rows + " row inserted");
}

READ — SELECT All Employees

String sql = "SELECT id, name, dept, salary FROM employees";

try (PreparedStatement pstmt = con.prepareStatement(sql);
     ResultSet rs = pstmt.executeQuery()) {

    while (rs.next()) {
        System.out.println(
            rs.getInt("id") + " | " +
            rs.getString("name") + " | " +
            rs.getString("dept") + " | " +
            rs.getDouble("salary")
        );
    }
}

READ — SELECT with WHERE (find by department)

String sql = "SELECT * FROM employees WHERE dept = ?";

try (PreparedStatement pstmt = con.prepareStatement(sql)) {
    pstmt.setString(1, "IT");
    ResultSet rs = pstmt.executeQuery();

    while (rs.next()) {
        System.out.println(rs.getString("name") + " — " + rs.getDouble("salary"));
    }
}

UPDATE — Change Salary

String sql = "UPDATE employees SET salary = ? WHERE id = ?";

try (PreparedStatement pstmt = con.prepareStatement(sql)) {
    pstmt.setDouble(1, 85000.0);  // new salary
    pstmt.setInt(2, 101);         // employee ID

    int rows = pstmt.executeUpdate();
    System.out.println(rows + " row(s) updated");
}

DELETE — Remove an Employee

String sql = "DELETE FROM employees WHERE id = ?";

try (PreparedStatement pstmt = con.prepareStatement(sql)) {
    pstmt.setInt(1, 101);          // ID to delete

    int rows = pstmt.executeUpdate();
    System.out.println(rows + " row(s) deleted");
}

12. Transaction Management

By default, JDBC runs in auto-commit mode — every SQL statement is committed immediately. But sometimes you need multiple statements to succeed or fail together.

Analogy — Bank Transfer
Transferring Rs. 5000 from Account A to Account B requires two SQL statements:
1. Deduct 5000 from A → UPDATE accounts SET balance = balance - 5000 WHERE id = 'A'
2. Add 5000 to B → UPDATE accounts SET balance = balance + 5000 WHERE id = 'B'

What if Step 1 succeeds but Step 2 fails? Money vanishes! That's why we need transactions — both must succeed, or both must be undone (rolled back).
try {
    con.setAutoCommit(false);   // Step 1: Turn OFF auto-commit

    // Step 2: Execute multiple statements
    PreparedStatement ps1 = con.prepareStatement(
        "UPDATE accounts SET balance = balance - ? WHERE id = ?");
    ps1.setDouble(1, 5000);
    ps1.setString(2, "A");
    ps1.executeUpdate();

    PreparedStatement ps2 = con.prepareStatement(
        "UPDATE accounts SET balance = balance + ? WHERE id = ?");
    ps2.setDouble(1, 5000);
    ps2.setString(2, "B");
    ps2.executeUpdate();

    con.commit();                // Step 3: All good — COMMIT both
    System.out.println("Transfer successful!");

} catch (SQLException e) {
    con.rollback();              // Step 4: Something failed — ROLLBACK both
    System.out.println("Transfer failed, rolled back.");
    e.printStackTrace();
} finally {
    con.setAutoCommit(true);    // Reset auto-commit
}

Savepoints

A Savepoint marks a point within a transaction. You can rollback to a savepoint instead of rolling back the entire transaction.

con.setAutoCommit(false);

stmt.executeUpdate("INSERT INTO logs VALUES (1, 'Step 1 done')");

Savepoint sp = con.setSavepoint("afterStep1");  // Mark this point

stmt.executeUpdate("INSERT INTO logs VALUES (2, 'Step 2 done')");

// Oops, Step 2 was wrong — rollback only Step 2
con.rollback(sp);   // Rolls back to savepoint — Step 1 is still intact

con.commit();        // Commits Step 1 only
Transaction Methods Summary
setAutoCommit(false) — start manual transaction
commit() — save all changes permanently
rollback() — undo all changes since last commit
setSavepoint("name") — create a checkpoint
rollback(savepoint) — undo changes to a specific checkpoint

13. Batch Processing

When you need to insert 100 or 1000 rows, running them one by one is slow. Batch processing sends multiple SQL statements to the database in one go.

String sql = "INSERT INTO employees (name, dept, salary) VALUES (?, ?, ?)";
PreparedStatement pstmt = con.prepareStatement(sql);

con.setAutoCommit(false);   // Use transaction for batch

// Add row 1 to batch
pstmt.setString(1, "Alice");
pstmt.setString(2, "HR");
pstmt.setDouble(3, 50000);
pstmt.addBatch();              // Add to batch — not executed yet

// Add row 2 to batch
pstmt.setString(1, "Bob");
pstmt.setString(2, "IT");
pstmt.setDouble(3, 60000);
pstmt.addBatch();

// Add row 3 to batch
pstmt.setString(1, "Charlie");
pstmt.setString(2, "Finance");
pstmt.setDouble(3, 55000);
pstmt.addBatch();

int[] results = pstmt.executeBatch();  // Execute all 3 at once!
con.commit();                           // Commit the transaction

System.out.println("Inserted " + results.length + " rows");
Batch Methods
addBatch() — adds the current parameters to the batch
executeBatch() — sends all batched statements to the DB at once, returns int[]
clearBatch() — clears the current batch without executing

14. Connection Pooling (Brief)

Creating a new database connection is expensive (takes time and resources). In a real web app, hundreds of users hit the server — creating a new connection for each request is wasteful.

Connection Pooling = keep a pool of pre-created connections ready. When a request comes, grab one from the pool. When done, return it to the pool instead of closing it.

Without Pooling vs With Pooling
Without: User request → Create connection → Use → Close → (next request creates another) — Slow
With: App starts → Create 10 connections in pool → User request → Grab one → Use → Return to pool — Fast

Popular Connection Pool Libraries

LibraryNotes
HikariCPFastest. Default in Spring Boot. Industry standard.
Apache DBCPOlder but still used. Part of Apache Commons.
C3P0Legacy. Rarely used in new projects.
Exam Note
You won't need to write connection pooling code in TCS exams. Just know what it is and why it's used. Answer: "Reuses connections for better performance instead of creating new ones each time."

15. Common JDBC Exceptions

ExceptionWhen It HappensFix
ClassNotFoundException Driver JAR not in classpath Add mysql-connector-j.jar to your project
SQLException Any SQL or connection error Check SQL syntax, URL, credentials
Communications link failure Database server is not running Start MySQL server
Access denied for user Wrong username or password Check credentials in getConnection()
Unknown database 'xyz' Database name in URL doesn't exist Create the database or fix the name
No suitable driver found Wrong URL format or driver not loaded Check URL starts with jdbc:mysql://
Debugging Tip
When you get a SQLException, always print:
e.getMessage() — what went wrong
e.getSQLState() — standard SQL error code
e.getErrorCode() — database-specific error code

16. Practice Questions

Question 1

Which of the following is the correct order of JDBC steps?

  1. Import → Load Driver → Create Statement → Establish Connection → Execute → Process → Close
  2. Import → Load Driver → Establish Connection → Create Statement → Execute → Process → Close
  3. Load Driver → Import → Establish Connection → Execute → Create Statement → Process → Close
  4. Import → Establish Connection → Load Driver → Create Statement → Execute → Process → Close
B) Import → Load Driver → Establish Connection → Create Statement → Execute → Process → Close. You must establish a connection before creating a statement.
Question 2

What does Class.forName("com.mysql.cj.jdbc.Driver") do?

  1. Creates a database connection
  2. Loads the JDBC driver class into JVM memory
  3. Executes a SQL query
  4. Creates a Statement object
B) It loads the driver class into JVM memory. The driver's static initializer block registers it with DriverManager automatically.
Question 3

Which Statement type prevents SQL injection?

  1. Statement
  2. PreparedStatement
  3. CallableStatement
  4. Both B and C
D) Both PreparedStatement and CallableStatement use parameterized queries, which prevent SQL injection. Statement uses string concatenation and is vulnerable.
Question 4

What does executeUpdate() return?

  1. ResultSet
  2. boolean
  3. int (number of rows affected)
  4. void
C) executeUpdate() returns an int representing the number of rows affected by INSERT, UPDATE, or DELETE operations.
Question 5

What does executeQuery() return?

  1. int
  2. boolean
  3. ResultSet
  4. String
C) executeQuery() returns a ResultSet object containing the rows returned by the SELECT query.
Question 6

In a PreparedStatement, what does the ? represent?

  1. A comment in SQL
  2. A wildcard character
  3. A parameter placeholder
  4. A null value
C) The ? is a parameter placeholder. You set its value using methods like setString(1, "value") or setInt(1, 42). Index starts at 1.
Question 7

Which is the correct JDBC URL for connecting to a MySQL database named "testdb" on localhost?

  1. mysql://localhost:3306/testdb
  2. jdbc:mysql://localhost:3306/testdb
  3. jdbc://mysql:localhost:3306/testdb
  4. jdbc:mysql:localhost:3306:testdb
B) The correct format is jdbc:mysql://hostname:port/database. The protocol is jdbc:mysql:// followed by host, port, and database name separated by / not colons.
Question 8

Which method is used to establish a connection in JDBC?

  1. Connection.open(url)
  2. DriverManager.getConnection(url, user, password)
  3. Driver.connect(url)
  4. Database.open(url, user, password)
B) DriverManager.getConnection(url, user, password) is the standard method to establish a JDBC connection.
Question 9

What is the default ResultSet type in JDBC?

  1. TYPE_SCROLL_INSENSITIVE
  2. TYPE_SCROLL_SENSITIVE
  3. TYPE_FORWARD_ONLY
  4. TYPE_RANDOM_ACCESS
C) TYPE_FORWARD_ONLY is the default. You can only call next() to move forward. To use previous(), first(), last(), you need a scrollable ResultSet.
Question 10

Which method is used to move the ResultSet cursor to the next row?

  1. rs.moveNext()
  2. rs.forward()
  3. rs.next()
  4. rs.advance()
C) rs.next() moves the cursor to the next row and returns true if there is a row, false if no more rows exist.
Question 11

To manually control transactions, what must you do first?

  1. Call con.beginTransaction()
  2. Call con.setAutoCommit(false)
  3. Call con.startTransaction()
  4. Call con.disableAutoCommit()
B) con.setAutoCommit(false) disables auto-commit mode. After this, changes are only saved when you explicitly call con.commit().
Question 12

What happens if a transaction fails and you call con.rollback()?

  1. All changes since the last commit are undone
  2. Only the last statement is undone
  3. The connection is closed
  4. The database is reset to initial state
A) rollback() undoes ALL changes made since the last commit (or since setAutoCommit(false) was called). The database returns to the state it was in before the transaction started.
Question 13

Which JDBC driver type is the most commonly used and is written entirely in Java?

  1. Type 1 — JDBC-ODBC Bridge
  2. Type 2 — Native API
  3. Type 3 — Network Protocol
  4. Type 4 — Thin/Pure Java
D) Type 4 (Thin/Pure Java) is the most used. It communicates directly with the database using Java sockets. MySQL Connector/J is a Type 4 driver.
Question 14

What exception is thrown when the JDBC driver JAR is not found in the classpath?

  1. SQLException
  2. IOException
  3. ClassNotFoundException
  4. DriverNotFoundException
C) ClassNotFoundException is thrown by Class.forName() when the driver class cannot be found, which means the driver JAR is not on the classpath.
Question 15

Which method is used to add SQL commands to a batch?

  1. addQuery()
  2. addSQL()
  3. addBatch()
  4. batchAdd()
C) addBatch() adds the current SQL statement (with its parameters) to the batch. executeBatch() then sends all batched statements to the database at once.
Question 16

In PreparedStatement, what is the index of the first parameter placeholder?

  1. 0
  2. 1
  3. -1
  4. Depends on the database
B) Parameter indices in PreparedStatement start at 1, not 0. This is different from arrays and lists in Java which start at 0.
Question 17

What is the purpose of connection pooling?

  1. To encrypt database connections
  2. To reuse existing connections instead of creating new ones each time
  3. To connect to multiple databases simultaneously
  4. To store SQL queries in memory for faster execution
B) Connection pooling maintains a pool of pre-created database connections. Instead of creating and destroying connections for every request (which is expensive), connections are borrowed from and returned to the pool.
Question 18

Which interface is used to call stored procedures in JDBC?

  1. Statement
  2. PreparedStatement
  3. CallableStatement
  4. StoredProcedureStatement
C) CallableStatement is used to call stored procedures. It is created using con.prepareCall("{call procedureName(?, ?)}").