- Explain the role of JDBC and compare the 4 JDBC Driver Types (Bridge, Native-API, Network-Protocol, Thin Pure-Java).
- Write and execute the standard 5-step JDBC database connection code.
- Differentiate
Statement,PreparedStatement, andCallableStatementand explain how PreparedStatement prevents SQL Injection. - Navigate and manipulate data using the
ResultSetinterface. - Extract structural database schema information using
DatabaseMetaDataandResultSetMetaData. - Implement manual ACID transaction management using
commit(),rollback(), and savepoints.
Every database engine speaks its own proprietary network dialect: Oracle uses TNS, MySQL uses MySQL Wire Protocol, SQL Server uses TDS, and PostgreSQL uses its own binary protocol. If Java had to build custom networking code for every single database brand, Java applications would be tightly coupled, non-portable, and impossible to maintain.
**JDBC (Java Database Connectivity)** provides a unified, standardized Java API (
java.sql). A Java developer writes standard SQL code once, and a vendor-supplied **JDBC Driver** translates those standard Java method calls into the specific low-level wire protocol required by that database!
JDBC is a standard Java API (java.sql and javax.sql) that enables Java programs to connect to relational databases, execute SQL queries, and retrieve results in an object-oriented manner.
| Driver Type | Name & Architecture | How It Works | Advantages & Disadvantages |
|---|---|---|---|
| Type 1 | JDBC-ODBC Bridge Driver | Translates JDBC calls into Microsoft ODBC calls, which then communicate with the database. | Pros: Connects to any database with an ODBC driver. Cons: Slow; requires native ODBC client software on every machine; completely removed in Java 8! |
| Type 2 | Native-API Partly-Java Driver | Converts JDBC calls directly into native C/C++ client library calls provided by the database vendor (e.g. Oracle OCI). | Pros: Faster than Type 1. Cons: Requires vendor-specific native client software installed on every client machine; platform dependent. |
| Type 3 | Network-Protocol Driver (Middleware) | Converts JDBC calls into a generic net-protocol sent to an intermediate Middleware Server, which translates them into vendor protocols. | Pros: 100% pure Java on client; no native client software required; switch databases without changing client. Cons: Requires maintaining an extra middleware application server. |
| Type 4 | Thin Driver (Direct Native Protocol) | 100% Pure Java: Converts JDBC calls directly into the database vendor's native network wire protocol over TCP/IP sockets. | Pros: Fastest performance; completely portable; zero client software or middleware needed (industry standard today!). Cons: Vendor-specific (need different JAR for MySQL, Oracle, Postgres). |
Every standard JDBC database interaction follows these 5 sequential steps:
- Step 1: Load and Register Driver: Dynamically load the vendor driver class using
Class.forName("com.mysql.cj.jdbc.Driver");. - Step 2: Establish the Database Connection: Call
DriverManager.getConnection(url, user, password);to obtain an active physical TCP socket session. - Step 3: Create a Statement Object: Create a
StatementorPreparedStatementto hold and transmit SQL statements. - Step 4: Execute the SQL Query: Use
executeQuery()forSELECT(returnsResultSet) orexecuteUpdate()forINSERT/UPDATE/DELETE(returns integer rows affected). - Step 5: Close Resources: Explicitly close
ResultSet,Statement, andConnectionto prevent database connection leaks.
Complete Runnable Code Example (10-Mark Model Answer):
import java.sql.*;
public class JdbcStudentDemo {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/college_db";
String user = "root";
String pass = "password";
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
// Step 1: Register Driver
Class.forName("com.mysql.cj.jdbc.Driver");
// Step 2: Establish Connection
con = DriverManager.getConnection(url, user, pass);
System.out.println("Connection established successfully!");
// Step 3: Create Statement
stmt = con.createStatement();
// Step 4: Execute Query
String sql = "SELECT roll_no, name, marks FROM students";
rs = stmt.executeQuery(sql);
System.out.println("Roll\tName\tMarks");
while (rs.next()) {
int roll = rs.getInt("roll_no");
String name = rs.getString("name");
double marks = rs.getDouble("marks");
System.out.println(roll + "\t" + name + "\t" + marks);
}
} catch (ClassNotFoundException e) {
System.out.println("Driver Class Not Found: " + e.getMessage());
} catch (SQLException e) {
System.out.println("Database Error: " + e.getMessage());
} finally {
// Step 5: Clean up resources
try {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (con != null) con.close();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
}
| Evaluation Parameter | Statement | PreparedStatement | CallableStatement |
|---|---|---|---|
| Precompilation | Compiled by database engine every single time query runs. | Precompiled once by database; execution plan is cached and reused. | Precompiled stored procedure inside the database. |
| Parameters Support | Does NOT support parameters; values must be concatenated as strings (e.g. "WHERE id=" + id). |
Supports parameterized queries using positional placeholders (?). |
Supports IN, OUT, and INOUT parameters. |
| SQL Injection Security | Vulnerable to SQL Injection: malicious input alters the SQL grammar structure. | 100% Immune to SQL Injection: input is treated strictly as literal data, never executable SQL! | Protected (precompiled stored procedures). |
| Performance | Slow for repeated queries (re-parses SQL every execution). | High performance for repeated execution (batch processing). | Highest performance for complex business logic. |
How PreparedStatement Prevents SQL Injection:
In a standard Statement, an attacker entering ' OR '1'='1 as a password creates:
SELECT * FROM users WHERE user = 'admin' AND pass = '' OR '1'='1'
This evaluates to TRUE and grants unauthorized access! With PreparedStatement:
String query = "SELECT * FROM users WHERE user = ? AND pass = ?";
PreparedStatement pstmt = con.prepareStatement(query);
pstmt.setString(1, userInput);
pstmt.setString(2, passInput);
ResultSet rs = pstmt.executeQuery();
The database precompiles the SQL command structure first. The parameter values are sent separately across the wire and bound strictly as data literalsβeven if an attacker enters quotes or SQL keywords, they are treated as harmless characters!
A ResultSet maintains a cursor pointing to its current row of data. Initially, the cursor is positioned before the first row.
| Cursor Method | Action Performed |
|---|---|
rs.next() |
Moves cursor forward one row. Returns true if row exists; false when end of results reached. |
rs.previous() |
Moves cursor backward one row (requires scrollable ResultSet). |
rs.first() / rs.last() |
Jumps directly to the very first / last row of the result set. |
rs.absolute(rowNumber) |
Jumps directly to the specified row index (positive from beginning, negative from end). |
DatabaseMetaData vs. ResultSetMetaData:
| Feature | DatabaseMetaData (con.getMetaData()) |
ResultSetMetaData (rs.getMetaData()) |
|---|---|---|
| Source | Obtained from the Connection object. |
Obtained from an active ResultSet object. |
| Scope | Enterprise-wide database software information. | Schema details of the specific query result columns. |
| Useful Methods | getDatabaseProductName(), getDatabaseProductVersion(), getDriverName() |
getColumnCount(), getColumnName(i), getColumnTypeName(i) |
By default, JDBC operates in auto-commit mode: every individual SQL query is committed to the database immediately upon execution. In financial transactions (like transferring money from Account A to Account B), both debit and credit operations must succeed together, or neither should occur.
try {
// Disable auto-commit to begin manual transaction
con.setAutoCommit(false);
PreparedStatement debit = con.prepareStatement("UPDATE accounts SET balance = balance - 500 WHERE id = 1");
debit.executeUpdate();
PreparedStatement credit = con.prepareStatement("UPDATE accounts SET balance = balance + 500 WHERE id = 2");
credit.executeUpdate();
// If both queries succeed without exception, commit transaction permanently
con.commit();
System.out.println("Transaction committed successfully!");
} catch (SQLException e) {
// If any error occurs, rollback all modifications back to original state!
try {
if (con != null) con.rollback();
System.out.println("Transaction rolled back due to error!");
} catch (SQLException ex) {
ex.printStackTrace();
}
}
- Definition (1 Mark): Define JDBC driver as a software component enabling Java applications to interact with database engines.
- 4 Diagrams (4 Marks): Draw a small 3-box architecture diagram for each driver type:
Type 1: Java App $\to$ JDBC $\to$ ODBC Driver $\to$ Database
Type 2: Java App $\to$ JDBC $\to$ Vendor Native C API $\to$ Database
Type 3: Java App $\to$ Net Protocol $\to$ Middleware Server $\to$ Database
Type 4: Java App $\to$ Pure Java Thin Driver (Direct TCP Sockets) $\to$ Database - Pros and Cons Table (4 Marks): Highlight that Type 4 is pure Java and fastest; Type 1 is deprecated.
- Conclusion (1 Mark): Recommend Type 4 for modern production systems.
β’ Confusing
executeQuery() with executeUpdate(): executeQuery() is strictly for SELECT queries. executeUpdate() is for INSERT, UPDATE, DELETE, CREATE.β’ Forgetting to Close Connections: In oral exams and written evaluations, forgetting
con.close() in a finally block loses 2 marks!
Verify your conceptual grasp across JDBC architecture, 4 driver types, PreparedStatements, ResultSets, and transaction control with this 10-question quiz.