JDBC
JDBC
What is JDBC?
JDBC (Java Database Connectivity) is an API (Application
Programming Interface) provided by Java to enable Java
applications to interact with relational databases.
NOTE: JDBC (Java Database Connectivity) is a part of J2SE/Java SE
(Java Standard Edition).
What is an API?
An API is a set of rules that allow different software applications
to communicate with each other. Think of it like a bridge that
connects two systems and lets them share data or services.
The JDBC API is a set of interfaces and classes in the java.sql and
javax.sql packages that allow Java programs to connect to,
communicate with, and perform operations on relational
databases.
With JDBC:
You write code using the standard JDBC interfaces.
When switching databases, you just change the driver and
connection URL.
The rest of the code remains the same.
This ensures database independence and reduces vendor lock-in.
NOTE:
Why is it called a "Driver" and not just a "Library"?
A driver is a special kind of library whose main job is to "drive" or
mediate communication between two systems — usually, your
program and an external resource (like a database or hardware).
DAY 2:
Disadvantages of File I/O (Compared to JDBC / DBMS)
1.Lack of Security
File I/O is not secure by default. Anyone with access to the file
system can view or modify data easily.
2.Data Redundancy
There may be duplicate data entries, as file systems do not
enforce rules to prevent duplication.
3.Data Inconsistency
If the same data is stored in multiple files or locations, it can
become inconsistent.
Example:
CIVIL Dept: 11 Raju 90888 CSK
Library: 11 Raju 80888 CSK
The phone numbers are different for the same person, leading to
inconsistency.
4.Atomicity Problem
File I/O does not support atomic transactions.
NOTE:
An atomic transaction means a series of operations that are
treated as a single, indivisible unit of work. It either completes
entirely or doesn't happen at all — there's no in-between.
JDBC CONNECTION:
A JDBC (Java Database Connectivity) connection refers to the
mechanism used by Java applications to interact with databases. It
allows Java programs to connect to databases, execute SQL queries, and
process the results.
So, now let’s explore the steps to connect to a database using JDBC.
Load the JDBC Driver (optional in JDBC 4.0+).
Establish a Connection using DriverManager.getConnection().
Before JDBC 4.0, developers had to explicitly load the JDBC driver using
Class.forName("driver-class-name") to register it with the
DriverManager. This was necessary for the Java application to recognize
and use the driver. However, starting from JDBC 4.0 (supported from
Java 6 onwards), this step is no longer required. Driver loading is now
NOTE:
To check the JDBC version being used
Find the JDBC Driver JAR file (e.g., mysql-connector-java-
8.0.xx.jar):
Open the JAR file using any ZIP tool or built-in file explorer.
Navigate to the file: ( META-INF/MANIFEST.MF )
Open this MANIFEST.MF file and look for attributes like:
Specification-Version: 4.2
Implementation-Version: 8.0.33
==========PROGRAM: JDBC-CONNECTION==========
package com.mainapp;
import java.sql.Connection;
import java.sql.DriverManager;
public class Launch {
public static void main(String[] args) {
try
{
//MYSQL DRIVER LOADED AND REGISTERED
//
Class.forName("com.mysql.cj.jdbc.Driver"); //JDBC
4.0+
String url="jdbc:mysql://localhost:3306";
String username="root";
String password="";
}
}
Explanation:
Connection con = DriverManager.getConnection(url,
user, pass);
You're actually getting an object of a class that
implements the Connection interface.
This is a classic example of the Factory Design
Pattern in action!
To do this, you need to understand some basic SQL commands, such as:
We’ve provided helpful video links below to help you learn these SQL
basics before moving forward with JDBC CRUD operations.
SQL LECTURES:
Lect1:
https://youtu.be/FEuugXBe_7k
Lect2:
https://youtu.be/7myDOv67lKk
Lect3:
https://youtu.be/Vfdw-6vYt2A
Lect4:
https://youtu.be/QpMNCDOM9_M
Lect5:
https://youtu.be/PNV9vC7_2zo
Lect6:
https://youtu.be/-ItBuLY3iwA
Lect7:
https://youtu.be/JJq0dSE4gag
Lect8:
https://youtu.be/-FqvJRPKoUk?si=VNYHZhWYu18JeILl
Lect9:
https://youtu.be/epZVdXdns-U
Lect10:
https://youtu.be/L9g-0neh_Gg
Lect11:
https://youtu.be/DzgiBCtAt8Q
DAY 3:
Now that we’ve successfully connected to the database, the next step is
to interact with it — this means performing real operations like
inserting data, retrieving records, updating existing entries, and deleting
unnecessary data. In simple terms, we’ll now start doing the actual
CRUD operations (Create, Read, Update, Delete) using JDBC.
To interact with the database, the JDBC API provides three main
interfaces:
Statement Interface
PreparedStatement Interface
CallableStatement Interface
package tech.codehunt.start;
import tech.codehunt.logic.Logic;
public class Launch {
}
}
package tech.codehunt.logic;
import java.util.Scanner;
import tech.codehunt.crud.Crud;
import tech.codehunt.dto.EmployeeDTO;
public class Logic {
public Logic() {
crud=new Crud();
}
while (true) {
System.out.println("\n=========MENU=========");
System.out.println("Press-1 : INSERT
DATA");
System.out.println("Press-2 : READ
DATA");
System.out.println("Press-3 : UPDATE
DATA");
System.out.println("Press-4 : DELETE
DATA");
System.out.println("Press-5 : EXIT\n");
try {
choice = scanner.nextInt();
} catch (Exception e) {
System.out.print("Invalid Input!
Please take a number from 1 to 5.\n");
scanner.nextLine();
attempt++;
if(attempt>=MAX_ATTEMPTS) {
System.out.print("You have
reached the limit");
scanner.close();
return;
}
continue;
}
switch (choice) {
case INSERT_DATA:
System.out.println("*************INSERT
DATA************");
System.out.println("ENTER USERNAME");
username=scanner.next();
System.out.println("ENTER PASSWORD");
password=scanner.next();
scanner.nextLine();
System.out.println("ENTER FULLNAME");
fullname=scanner.nextLine();
System.out.println("ENTER ADDRESS");
address=scanner.nextLine();
System.out.println("ENTER SALARY");
salary=scanner.nextInt();
crud.insert(employeeDTO);
break;
case READ_DATA:
System.out.println("******************READ
DATA********************");
System.out.println("ENTER USERNAME");
username=scanner.next();
System.out.println("ENTER PASSWORD");
password=scanner.next();
crud.read(username, password);
break;
case UPDATE_DATA:
System.out.println("*********************UPDATE
DATA*****************");
System.out.println("ENTER USERNAME");
username=scanner.next();
System.out.println("ENTER SALARY");
salary=scanner.nextInt();
crud.update(username, salary);
break;
case DELETE_DATA:
System.out.println("ENTER USERNAME");
username=scanner.next();
crud.delete(username);
System.out.println("*********************DELETE
DATA*****************");
break;
case EXIT:
System.out.println("EXIT");
scanner.close();
return;
}//switch
}//while
}//doStart
}
package tech.codehunt.crud;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import tech.codehunt.dto.EmployeeDTO;
public Crud() {
createTable();
connection =
ConnectionFactory.getConnection();// CONNECTION MANAGE
String sql = "CREATE TABLE IF NOT EXISTS
employee(sn INT AUTO_INCREMENT PRIMARY KEY,"
+ "USERNAME varchar(30) NOT NULL
UNIQUE," + "PASSWORD varchar(30)," + "FULLNAME
varchar(100),"
+ "ADDRESS varchar(200)," +
"SALARY int)";
statement = connection.createStatement();
statement.executeUpdate(sql);
System.out.println("TABLE CREATED");
} catch (Exception e) {
e.printStackTrace();
} finally {
ConnectionFactory.close(statement);
ConnectionFactory.close(connection);
}
}
try {
String sql = "insert into
employee(username,password,fullname,address,salary) "
+ "values ('"
+ employeeDTO.getUsername() +
"','" + employeeDTO.getPassword() + "','" +
employeeDTO.getFullname()
+ "','" +
employeeDTO.getAddress() + "'," +
employeeDTO.getSalary() + ")";
connection =
ConnectionFactory.getConnection();
statement = connection.createStatement();
statement.executeUpdate(sql);
System.out.println("DATA INSERTED");
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionFactory.close(statement);
ConnectionFactory.close(connection);
}
}
try {
connection =
ConnectionFactory.getConnection();
statement = connection.createStatement();
resultSet = statement.executeQuery(sql);
// NO DATA
if (resultSet.next()) {
int getSn = resultSet.getInt("sn");
String getUsername =
resultSet.getString("username");
String getPassword =
resultSet.getString("password");
String getFullname =
resultSet.getString("fullname");
String getAddress =
resultSet.getString("address");
int getSalary =
resultSet.getInt("salary");
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionFactory.close(resultSet);
ConnectionFactory.close(statement);
ConnectionFactory.close(connection);
}
}
try {
String sql = "update employee set
salary=" + salary + " where username='" + username +
"'";
connection =
ConnectionFactory.getConnection();
statement = connection.createStatement();
int executeUpdate =
statement.executeUpdate(sql); // NO DATA
if (executeUpdate > 0) {
System.out.println("DATA UPDATED");
} else {
System.out.println("USER NOT FOUND");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionFactory.close(statement);
ConnectionFactory.close(connection);
}
try {
package tech.codehunt.dto;
public class EmployeeDTO {
public EmployeeDTO() {
// TODO Auto-generated constructor stub
}
package tech.codehunt.crud;
import java.sql.Connection;
import java.sql.DriverManager;
public class ConnectionFactory {
Connection connection=null;
try {
connection=DriverManager.getConnection(DB_URL,DB_U
SER,DB_PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
return connection;
CODE EXPLANATION
NUMBER-1: Why is it important to close Connection,
Statement, and ResultSet in JDBC?
It's important to close these JDBC resources for the following reasons:
Prevent Resource Leakage – These objects consume system
and database resources. Not closing them can lead to memory
leaks.
Avoid Connection Pool Exhaustion – If connections aren’t
closed, they’re not returned to the pool, causing “Too many
connections” errors.
Release Database Locks – Open statements or result sets can
hold database locks, blocking other operations.
Improve Performance and Stability – Promptly closing
resources ensures smoother application behaviour and avoids
crashes.
NOTE:
Closing the Connection will automatically close all associated Statement
and ResultSet objects.
So technically, it won’t cause a memory leak, and no exception will be
thrown.
BUT…
Why you still should close the Statement or ResultSet explicitly:
Best Practice / Readability:
It’s clear and intentional.
Prevents bugs if someone reuses the connection later in the code.
In the case of the Statement interface, we can say that input data is
treated as part of the query — and that's exactly why SQL injection
becomes possible.
' OR '1'='1
In this case, the input is no longer just data — it's actually being treated
as part of the SQL query. That’s dangerous.
That's Why You Should Use Statement Only for Static queries (Queries
that don't involve user input Ex. DDL)
NUMBER-3: Why Statement Interface?
Why Can't We Directly Execute SQL on Connection?
The Connection interface in JDBC is designed to manage the
connection to the database itself — not to execute SQL
commands directly. It serves as the link between your Java
program and the database, handling transaction management,
connection pooling, and other aspects of the connection lifecycle.
Use Case:
When you don't know in advance if the SQL will return a result set
or not. It's a "catch-all" method that can be used for any SQL
command.
2. executeUpdate()
Purpose:
Executes SQL commands that modify the database (e.g., INSERT,
UPDATE, DELETE, CREATE, DROP). It does not return a ResultSet.
Instead, it returns an integer representing the number of rows
affected by the SQL query.
Return Type:
int (the number of rows affected)
Use Case:
When you're executing SQL that modifies the database (but
doesn't return data, like a SELECT query would). It's specifically
designed for Data Manipulation Language (DML) commands.
3. executeQuery()
Purpose:
Executes SQL queries that return a ResultSet (i.e., SELECT
statements). It is specifically designed for querying the database.
Return Type:
ResultSet (the data returned by the query)
Use Case:
When you know your SQL statement is a SELECT query that will
return data, and you want to retrieve that data in a ResultSet.
Working:
In JDBC, the ResultSet does not fetch all the data from the database
initially when the query is executed. Instead, it uses a cursor-based
approach, where the data is retrieved one row at a time as you navigate
through the result set. When the query is executed, the ResultSet is
created, but the cursor is positioned before the first row. Calling the
rs.next() method moves the cursor to the next row and retrieves the
data for that row. This means that the entire result set is not loaded
into memory at once, which helps optimize performance, especially
when dealing with large datasets. The data is fetched only when
needed, minimizing memory usage and allowing for more efficient
processing of the results.
So before calling rs.next():
The ResultSet does not point to any actual row yet.
It holds:
Metadata about the result (column names, data types, number of
columns, etc.).
A cursor that is set before the first row.
A connection to the actual query result on the database server.
DAY 4:
Up to this point, we’ve explored the Statement interface in JDBC,
understood its usage, and identified its major drawback—it is not
secure for handling user input, as it’s vulnerable to SQL injection. Now,
it’s time to move ahead and learn about the PreparedStatement
interface, which is specifically designed for secure and dynamic data
insertion.
PreparedStatement:
PreparedStatement is a sub-interface of Statement in JDBC that is used
to execute parameterized SQL queries.
Precompiled Query:
The SQL query is compiled once and can be reused multiple
times with different parameters.
package tech.codehunt.start;
import tech.codehunt.logic.Logic;
public class Launch {
public static void main(String[] args) {
}
}
package tech.codehunt.logic;
import java.util.Scanner;
import tech.codehunt.crud.Crud;
import tech.codehunt.dto.EmployeeDTO;
public class Logic {
public Logic() {
crud=new Crud();
}
while (true) {
System.out.println("\n=========MENU=========");
System.out.println("Press-1 : INSERT
DATA");
System.out.println("Press-2 : READ
DATA");
System.out.println("Press-3 : UPDATE
DATA");
System.out.println("Press-4 : DELETE
DATA");
System.out.println("Press-5 : TEST
DATA");
System.out.println("Press-6 : EXIT\n");
try {
choice = scanner.nextInt();
} catch (Exception e) {
System.out.print("Invalid Input!
Please take a number from 1 to 6.\n");
scanner.nextLine();
attempt++;
if(attempt>=MAX_ATTEMPTS) {
System.out.print("You have
reached the limit");
scanner.close();
return;
}
continue;
}
switch (choice) {
case INSERT_DATA:
System.out.println("*************INSERT
DATA************");
System.out.println("ENTER USERNAME");
username=scanner.next();
System.out.println("ENTER PASSWORD");
password=scanner.next();
scanner.nextLine();
System.out.println("ENTER FULLNAME");
fullname=scanner.nextLine();
System.out.println("ENTER ADDRESS");
address=scanner.nextLine();
System.out.println("ENTER SALARY");
salary=scanner.nextInt();
crud.insert(employeeDTO);
break;
case READ_DATA:
System.out.println("******************READ
DATA********************");
System.out.println("ENTER USERNAME");
username=scanner.next();
System.out.println("ENTER PASSWORD");
password=scanner.next();
crud.read(username, password);
break;
case UPDATE_DATA:
System.out.println("*********************UPDATE
DATA*****************");
System.out.println("ENTER USERNAME");
username=scanner.next();
System.out.println("ENTER SALARY");
salary=scanner.nextInt();
crud.update(username, salary);
break;
case DELETE_DATA:
System.out.println("*********************DELETE
DATA*****************");
System.out.println("ENTER USERNAME");
username=scanner.next();
crud.delete(username);
break;
case TEST_DATA:
System.out.println("*********************TEST
DATA*****************");
System.out.println("P1->SELECT\nP2-
>NON SELECT");
choice=scanner.nextInt();
if(choice==1) {
crud.test(sql1);
}else {
crud.test(sql2);
}
break;
case EXIT:
System.out.println("EXIT");
scanner.close();
return;
}//switch
}//while
}//doStart
}
package tech.codehunt.crud;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import tech.codehunt.dto.EmployeeDTO;
public Crud() {
createTable();
}
connection =
ConnectionFactory.getConnection();// CONNECTION MANAGE
String sql = "CREATE TABLE IF NOT EXISTS
employee(sn INT AUTO_INCREMENT PRIMARY KEY,"
+ "USERNAME varchar(30) NOT NULL
UNIQUE," + "PASSWORD varchar(30)," + "FULLNAME
varchar(100),"
+ "ADDRESS varchar(200)," +
"SALARY int)";
statement = connection.createStatement();
statement.executeUpdate(sql);
System.out.println("TABLE CREATED");
} catch (Exception e) {
e.printStackTrace();
} finally {
ConnectionFactory.close(statement);
ConnectionFactory.close(connection);
}
}
try {
String sql = "insert into
employee(username,password,fullname,address,salary)
values(?,?,?,?,?)";
connection =
ConnectionFactory.getConnection();
preparedStatement =
connection.prepareStatement(sql); // COMPILE->DATABASE
int count = 1;
while (count <= 5) {
preparedStatement.setString(1,
employeeDTO.getUsername()+count);
preparedStatement.setString(2,
employeeDTO.getPassword());
preparedStatement.setString(3,
employeeDTO.getFullname());
preparedStatement.setString(4,
employeeDTO.getAddress());
preparedStatement.setInt(5,
employeeDTO.getSalary());
preparedStatement.executeUpdate();
System.out.println("DATA INSERTED");
count++;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionFactory.close(preparedStatement);
ConnectionFactory.close(connection);
}
}
try {
connection =
ConnectionFactory.getConnection();
preparedStatement =
connection.prepareStatement(sql);
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
resultSet =
preparedStatement.executeQuery();
if (resultSet.next()) {
int getSn = resultSet.getInt("sn");
String getUsername =
resultSet.getString("username");
String getPassword =
resultSet.getString("password");
String getFullname =
resultSet.getString("fullname");
String getAddress =
resultSet.getString("address");
int getSalary =
resultSet.getInt("salary");
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionFactory.close(resultSet);
ConnectionFactory.close(preparedStatement);
ConnectionFactory.close(connection);
}
}
try {
String sql = "update employee set
salary=? where username=?";
connection =
ConnectionFactory.getConnection();
preparedStatement =
connection.prepareStatement(sql);
preparedStatement.setInt(1, salary);
preparedStatement.setString(2, username);
int executeUpdate =
preparedStatement.executeUpdate(); // NO DATA
if (executeUpdate > 0) {
System.out.println("DATA UPDATED");
} else {
System.out.println("USER NOT FOUND");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionFactory.close(preparedStatement);
ConnectionFactory.close(connection);
}
try {
preparedStatement.setString(1, username);
int executeUpdate =
preparedStatement.executeUpdate(); // NO DATA
if (executeUpdate > 0) {
System.out.println("DATA DELETED");
} else {
System.out.println("USER NOT FOUND");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionFactory.close(preparedStatement);
ConnectionFactory.close(connection);
}
}
try {
connection =
ConnectionFactory.getConnection();
preparedStatement =
connection.prepareStatement(sql);
boolean execute =
preparedStatement.execute();
if(execute) {
ResultSet resultSet =
preparedStatement.getResultSet();
if (resultSet.next()) {
int getSn =
resultSet.getInt("sn");
String getUsername =
resultSet.getString("username");
String getPassword =
resultSet.getString("password");
String getFullname =
resultSet.getString("fullname");
String getAddress =
resultSet.getString("address");
int getSalary =
resultSet.getInt("salary");
System.out.println("SN: " +
getSn);
System.out.println("USERNAME: "
+ getUsername);
System.out.println("PASSWORD: "
+ getPassword);
System.out.println("FULLNAME: "
+ getFullname);
System.out.println("ADDRESS: " +
getAddress);
System.out.println("SALARY: " +
getSalary);
} else {
System.out.println("USER NOT
FOUND");
}
}
else {
int k =
preparedStatement.getUpdateCount();
System.out.println(k);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionFactory.close(preparedStatement);
ConnectionFactory.close(connection);
}
}
}
package tech.codehunt.dto;
public class EmployeeDTO {
public EmployeeDTO() {
// TODO Auto-generated constructor stub
}
package tech.codehunt.crud;
import java.sql.Connection;
import java.sql.DriverManager;
public class ConnectionFactory {
Connection connection=null;
try {
connection=DriverManager.getConnection(DB_URL,DB_U
SER,DB_PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
return connection;
=============================
=============================
Query is Precompiled:
When you write a PreparedStatement like this:
String sql = "SELECT * FROM users WHERE
username = ? AND password = ?";
PreparedStatement ps =
conn.prepareStatement(sql);
The SQL query with placeholders (?) is sent to the database
server in advance and compiled. At this stage, the DB knows
the structure of the query, but not the actual data.
Parameters are Bound Safely: ( You then set the parameters like this )
ps.setString(1, userInputUsername);
ps.setString(2, userInputPassword);
These inputs are not merged into the SQL string. Instead,
they're sent separately to the database driver, which treats
them strictly as values, not part of the SQL syntax.
DAY 5:
CallableStatement
What is CallableStatement in JDBC?
A CallableStatement is a special type of JDBC statement used to
execute stored procedures in a relational database. It is part of
the java.sql package and is an extension(child) of
PreparedStatement.
Stored procedures are precompiled SQL code stored in the
database that can accept input parameters, return output
parameters, and even return result sets.
try
{
String
url="jdbc:mysql://localhost:3306/maybatch";
String username="root";
String password="";
Connection con =
DriverManager.getConnection(url,username,password);
CallableStatement callableStatement =
con.prepareCall("{CALL xyz(?,?)}");
callableStatement.setString(1, "j%");
callableStatement.setInt(2, 1000);
ResultSet rs =
callableStatement.executeQuery();
while(rs.next()) {
System.out.println(rs.getString("fullname"));
System.out.println(rs.getInt("salary"));
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
=============================================
=============================================
Why?
PreparedStatement is precompiled, but only per JDBC connection
and per statement object.
If you create a new PreparedStatement each time, the DB sees it
as a new statement and recompiles it.
So yes, compilation happens each time you call the method if
you're not reusing the PreparedStatement.
PreparedStatement ps =
connection.prepareStatement("SELECT ...");
for (int i = 0; i < 2; i++) {
ps.setInt(1, id);
ps.executeQuery();
}
But this preparation is very lightweight because the actual SQL logic is
already compiled in the DB.
JDBC TRANSCTION
MANAGEMENT
What is a Transaction?
A transaction is a group of one or more SQL statements that are
executed as a single unit of work. It ensures data integrity and
follows the principle of:
Atomicity
Atomicity means all operations in a transaction either complete
successfully together, or none of them take effect at all. If one
part fails, the entire transaction is rolled back, leaving the
database unchanged — as if nothing happened.
con =
DriverManager.getConnection(url,username,password);
con.setAutoCommit(false);
System.out.println("ENTER NEW
SALARY");//1000
preparedStatement.setInt(1,
scanner.nextInt() );
int executeUpdate1 =
preparedStatement.executeUpdate();
System.out.println(executeUpdate1);
Thread.sleep(10000);
System.out.println("ENTER NEW
SALARY");//2000
preparedStatement.setInt(1,
scanner.nextInt() );
int executeUpdate2 =
preparedStatement.executeUpdate();
System.out.println(executeUpdate2);
Thread.sleep(10000);
System.out.println("ENTER NEW
SALARY");//3000
preparedStatement.setInt(1,
scanner.nextInt() );
int executeUpdate3 =
preparedStatement.executeUpdate();
System.out.println(executeUpdate3);
con.commit();
}
catch (Exception e) {
try {
con.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
=============================================
=============================================
DAY 6:
Batch Processing
What is Batch Processing in JDBC?
Batch Processing allows you to group multiple SQL statements and send
them to the database in one go, instead of executing them one by one.
This reduces:
• Network calls
• Execution time
con = DriverManager.getConnection(url,
username, password);
con.setAutoCommit(false);
System.out.println(con);
while (true) {
System.out.println("ENTER USERNAME");
String user = scanner.next();
System.out.println("ENTER PASSWORD");
String pass = scanner.next();
scanner.nextLine();
System.out.println("ENTER FULLNAME");
String fullname = scanner.nextLine();
System.out.println("ENTER ADDRESS");
String address = scanner.nextLine();
System.out.println("ENTER SALARY");
int salary = scanner.nextInt();
preparedStatement.setString(1, user);
preparedStatement.setString(2, pass);
preparedStatement.setString(3,
fullname);
preparedStatement.setString(4,
address);
preparedStatement.setInt(5, salary);
preparedStatement.addBatch();
System.out.println("DO U WANT 2
INSERT MORE:(Y)");
String
choice=scanner.next().trim().toUpperCase();
if(!choice.equals("Y")) {
int[] i =
preparedStatement.executeBatch();
//Arrays.stream(i).forEach(n-
>System.out.println(n));
System.out.println("ROWS
INSERTED:-"+i.length);
con.commit();
break;
}
}
} catch (Exception e) {
try {
con.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
=============================================
=============================================
DAY 7:
MetaData
Metadata means "data about data".
In JDBC, metadata helps us get information about:
• The database (like DB name, version, tables)
• The ResultSet (columns, types, etc.)
con =
DriverManager.getConnection(url,username,password);
DatabaseMetaData metaData =
con.getMetaData();//FACTORY DESIGN PATTERN
String userName2 =
metaData.getUserName();
System.out.println(userName2);
String databaseProductName =
metaData.getDatabaseProductName();
String databaseProductVersion =
metaData.getDatabaseProductVersion();
int databaseMajorVersion =
metaData.getDatabaseMajorVersion();
int databaseMinorVersion =
metaData.getDatabaseMinorVersion();
System.out.println(databaseProductName);
System.out.println(databaseProductVersion);
System.out.println(databaseMajorVersion);
System.out.println(databaseMinorVersion);
String driverName =
metaData.getDriverName();
String driverVersion =
metaData.getDriverVersion();
int driverMajorVersion =
metaData.getDriverMajorVersion();
int driverMinorVersion =
metaData.getDriverMinorVersion();
System.out.println(driverName);
System.out.println(driverVersion);
System.out.println(driverMajorVersion);
System.out.println(driverMinorVersion);
int maxUserNameLength =
metaData.getMaxUserNameLength();
System.out.println(maxUserNameLength);
int maxColumnsInTable =
metaData.getMaxColumnsInTable();
System.out.println(maxColumnsInTable);
int maxRowSize =
metaData.getMaxRowSize();
System.out.println(maxRowSize);
}
catch (Exception e) {
try {
con.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
=============================================
=============================================
========PROGRAM-2: RESULTSET META DATA=======
package com.mainapp;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Scanner;
public class Launch {
public static void main(String[] args) {
con =
DriverManager.getConnection(url,username,password);
ResultSetMetaData metaData =
resultSet.getMetaData();
int columnCount =
metaData.getColumnCount();
System.out.println(columnCount);
for(int i=1;i<=columnCount;i++) {
String columnName =
metaData.getColumnName(i);
System.out.println(columnName);
}
for(int i=1;i<=columnCount;i++) {
String columnName =
metaData.getColumnClassName(i);
System.out.println(columnName);
}
for(int i=1;i<=columnCount;i++) {
int size=
metaData.getColumnDisplaySize(i);
System.out.println(size);
}
String tableName =
metaData.getTableName(1);
System.out.println(tableName);
String dbname =
metaData.getCatalogName(1);
System.out.println(dbname);
}
catch (Exception e) {
try {
con.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
=============================================
=============================================
DAY 8:
Connection with Properties
What is a JDBC Connection with Properties?
In JDBC, a connection using a Properties object means passing the
database username, password, and other settings separately
using key-value pairs instead of writing everything inside the
connection URL. This makes the code cleaner, easier to manage,
and more flexible for future changes. Typically, these properties
are loaded from an external .properties file, which helps in
keeping configuration separate from code and simplifies
environment-based setups.
(.properties vs .txt)
Feature Properties file
Text file
Format Key-value pairs (standardized)
Free-form text (no structure enforced)
Readable by Java ✅ Directly with Properties.load()
❌ Must read manually and parse(IF NOT IN KEY VALUE)
Purpose Configuration settings
Any general-purpose content
File extension .properties
.txt
Usage in Java projects Widely used (for config)
Rare for storing credentials
Scenario Works?
Recommended?
Key-value pairs in .properties file ✅ Java reads easily
✅ Yes, industry standard
Key-value pairs in .txt file ✅ Java reads if formatted
❌ No, avoid confusing use
=====PROGRAM: CONNECTION WITH PROPERTIES=====
package com.mainapp;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
try {
while (true) {
//FileInputStream fis = new
FileInputStream("C:\\Users\\DELL\\Desktop\\config\\myc
onfig.properties");
FileInputStream fis = new
FileInputStream("myconfig.properties");
Properties properties = new
Properties(); // KEY VALUE LOAD
properties.load(fis);
Connection connection =
DriverManager.getConnection(url, user, pass);
System.out.println(connection + " ->
" + connection.getCatalog());
Thread.sleep(2000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
=============================================
=============================================
Connection Pooling
What is Connection Pooling?
Connection pooling is a technique used to manage and optimize
database connections in applications.
Why is Connection Pooling needed?
• Opening and closing a database connection is expensive and slow —
it involves network overhead, authentication, and resource allocation.
• In web apps or enterprise apps, multiple requests often need to access
the database concurrently and repeatedly.
• Creating a new connection for every request hurts performance and
scalability.
EXAMPLE:
• If the pool has, say, 10 connections, then up to 10 threads can get
connections simultaneously.
• If the 11th thread asks for a connection while all 10 are in use, it will
either:
o Wait until a connection is returned (blocking call), or
o Get an error/timeout/Pool Grow, depending on pool config.
Analogy:
Imagine the pool as a locker room with 10 lockers (connections):
• Multiple people (threads) come to get a locker at the same time.
• The locker room has a system (thread-safety) to ensure no two people
get assigned the same locker simultaneously.
• If all lockers are taken, newcomers wait in line.
Possible behaviours:
Wait (blocking):
The 11th request waits for a connection to be returned to the pool
within a configured timeout. If a connection is returned in time,
the request gets it.
Reject immediately:
Some pools can be configured to reject new requests immediately
if the pool is exhausted.
NOTE:
JDBC itself does not have a built-in connection pool.
The core JDBC API (java.sql) only provides basic classes like
Connection, Statement, ResultSet, etc., and leaves connection
pooling up to the developer or external libraries.
✅ What is HikariCP?
HikariCP is a fast, lightweight, and reliable JDBC connection pooling
library (third party). It’s the default connection pool in Spring Boot
(since version 2.x) due to its performance and low overhead.
Download link:
Download jar file(search hikaricp without space in
mvnrepository.com(3.1.0))
https://mvnrepository.com/artifact/com.zaxxer/HikariCP
Downlaod jar file( search slf4j without space in
mvnrepository.com (1.7) (INTERNALLY HIKARI USES SLF4J)
https://mvnrepository.com/artifact/org.slf4j/slf4j-api/1.7.5
By default, it uses:
maximumPoolSize = 10 connections
idle connection = 10 connections
NOTE:
If you configure:
dataSource.setMinimumIdle(50); // Idle (ready-to-use)
connections
dataSource.setMaximumPoolSize(100); // Total connections
allowed
To fully release all resources and shut down the pool, you must
close the data source itself.
package com.mainapp;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
HikariDataSource hikariDataSource=null;
try {
//CONNECTION DETAILS---->HIKARI
hikariConfig.setJdbcUrl((String)properties.get("my
sql.url"));
hikariConfig.setUsername((String)properties.get("m
ysql.user"));
hikariConfig.setPassword((String)properties.get("m
ysql.pass"));
hikariConfig.setMinimumIdle(20);
hikariConfig.setMaximumPoolSize(100);
hikariDataSource=new
HikariDataSource(hikariConfig);//POOL READY
Connection connection =
hikariDataSource.getConnection();//GET FROM THE POOL
System.out.println(connection);
connection.close();//BACK TO POOL
} catch (Exception e) {
// TODO: handle exception
}
finally {
hikariDataSource.close();//CLOSING(COMPLETE POOL)
}
}
}
=============================================
=============================================
DAY 9:
RowSet
ResultSet always works with an active database connection.
NOTE:
The ResultSet in JDBC is not serializable because it maintains a live
connection with the database while accessing or modifying data. This
connection-dependent nature makes it unsuitable for scenarios where
the data needs to be transferred over a network or saved to a file. Since
ResultSet directly interacts with the database, any attempt to serialize it
would result in issues due to its dependency on an active database
connection. In contrast, RowSet implementations like CachedRowSet
are designed to be disconnected and serializable, allowing developers to
fetch data, work offline, and later sync changes—making them ideal for
distributed applications or offline data manipulation.
=============PROGRAM-1: ResultSet============
package com.mainapp;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Scanner;
public class Launch {
public static void main(String[] args) {
con = DriverManager.getConnection(url,
username, password);
System.out.println(con);
PreparedStatement ps =
con.prepareStatement("select * from employee",
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int sn = rs.getInt("sn");
String fullname =
rs.getString("fullname");
if (fullname.equals("wwww")) {
rs.deleteRow();
}
}
test(rs);
} catch (Exception e) {
e.printStackTrace();
}
}
try {
rs.beforeFirst();
while (rs.next()) {
int sn = rs.getInt("sn");
String fullname =
rs.getString("fullname");
System.out.println(sn);
System.out.println(fullname);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
=============================================
=============================================
===============PROGRAM-2: RowSet=============
package com.mainapp;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Scanner;
import javax.sql.rowset.CachedRowSet;
import javax.sql.rowset.RowSetProvider;
con = DriverManager.getConnection(url,
username, password);
System.out.println(con);
PreparedStatement ps =
con.prepareStatement("select * from employee",
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = ps.executeQuery();
CachedRowSet cachedRowSet =
RowSetProvider.newFactory().createCachedRowSet();
cachedRowSet.populate(rs); // CACHE
MEMORY //OFFLINE(NOT CONNECTED)
while (cachedRowSet.next()) {
int sn = cachedRowSet.getInt("sn");
String fullname =
cachedRowSet.getString("fullname");
if (fullname.equals("wwww")) {
cachedRowSet.deleteRow();
}
}
test(cachedRowSet);
} catch (Exception e) {
e.printStackTrace();
}
}
try {
cachedRowSet.beforeFirst();
while (cachedRowSet.next()) {
int sn = cachedRowSet.getInt("sn");
String fullname =
cachedRowSet.getString("fullname");
System.out.println(sn);
System.out.println(fullname);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
=============================================
=============================================