π§© 1. Understanding What a βDatabase Connectionβ Is
A Database Connection is a communication channel between your Java application and a database (e.g., MySQL, PostgreSQL, Oracle, etc.).
- It uses JDBC (Java Database Connectivity) under the hood.
-
A connection is required to:
- Execute queries
- Fetch / insert / update data
- Commit or rollback transactions
πͺ 2. Level 1 β Raw JDBC Connection (Manual Way)
This is the most basic way:
π You manually open and close a connection using DriverManager
.
π§ Concept
- Each time a request comes, app opens a new connection.
- No pooling or optimization.
- Good for learning, bad for production.
π§βπ» Example Code
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class RawJDBCExample {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/mydb";
String username = "root";
String password = "admin";
try {
// 1. Establish connection
Connection conn = DriverManager.getConnection(url, username, password);
System.out.println("β
Connected to DB");
// 2. Execute a query
String sql = "SELECT * FROM users WHERE id = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, 1);
ResultSet rs = stmt.executeQuery();
// 3. Process result
while (rs.next()) {
System.out.println("User: " + rs.getString("name"));
}
// 4. Close connection
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
β οΈ Problems
- β Creates new connection for each call (slow)
- β No retry or timeout control
- β Hard to manage in multi-threading
- β Code is tightly coupled to DB logic
β
Good for: Testing locally or tiny apps
π« Bad for: Real APIs, load testing, production apps
πͺ 3. Level 2 β Spring Boot + DataSource (DriverManagerDataSource)
Spring Boot allows us to define a DataSource
Bean, so we donβt manually open/close connections every time.
π§ Concept
-
DataSource
gives you a ready-made connection. - It can still use
DriverManager
underneath (no pool yet). - Spring injects the DataSource wherever you need it.
π§βπ» Example
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
@Configuration
public class DbConfig {
@Bean
public DataSource devDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mydb");
dataSource.setUsername("root");
dataSource.setPassword("admin");
return dataSource;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public String getUserNameById(int id) {
return jdbcTemplate.queryForObject(
"SELECT name FROM users WHERE id = ?",
new Object[]{id},
String.class
);
}
}
β‘ Advantages
- β Spring manages connection lifecycle
- β Cleaner code
- β οΈ Still no connection pool
β
Good for: Local apps, internal tools
π« Bad for: High-load systems
πͺ 4. Level 3 β Connection Pooling (HikariCP) β (Best Practice)
Spring Boot by default uses HikariCP β a fast, lightweight connection pool.
π Connection Pooling means:
- A fixed number of connections are created (e.g., 10)
- Requests reuse existing connections
- No time wasted opening/closing every time
π§ Concept Flow
- App starts β Hikari creates a pool (e.g., 10 connections)
- Request comes β Borrows connection from pool
- Query runs β Returns connection to pool
- Idle connections auto-managed (can shrink if needed)
- Multiple threads reuse pool efficiently
π§βπ» Configuration in application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# HikariCP specific
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=2
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.pool-name=MyHikariPool
π§βπ» Repository Example
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public int getUserCount() {
return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users", Integer.class);
}
}
β Best practice for production
- β‘ Reuses connections
- π§ Handles idle connections smartly
- π§° Avoids DB overload
- π§ͺ Ideal for high concurrency
πͺ 5. Level 4 β JPA / Hibernate (ORM Layer)
When your project grows, you may not want to write SQL queries manually.
π Thatβs where Spring Data JPA / Hibernate comes in.
π§ Concept
- ORM (Object Relational Mapping): maps your Java classes to DB tables
- No need to manually manage connections or queries
- Uses the same HikariCP pool underneath
π§βπ» Example Entity
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class User {
@Id
private int id;
private String name;
// getters and setters
}
π§βπ» Repository
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Integer> {
// No SQL needed, Spring generates queries
}
π§βπ» Service Layer
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final UserRepository userRepo;
public UserService(UserRepository userRepo) {
this.userRepo = userRepo;
}
public String getUserName(int id) {
return userRepo.findById(id).map(User::getName).orElse("Not Found");
}
}
β
Cleaner code
β
No manual connection handling
β
Connection pool under the hood (HikariCP)
π§ 6. Important Advanced Concepts
π§ a. Connection vs DataSource vs JdbcTemplate vs EntityManager
Layer | Responsibility | Example |
---|---|---|
Connection |
Low-level JDBC | DriverManager.getConnection() |
DataSource |
Connection provider |
DriverManagerDataSource or HikariDataSource
|
JdbcTemplate |
Simplifies JDBC calls | jdbcTemplate.query(...) |
EntityManager / JPA |
ORM mapping | userRepository.findById(1) |
π§ b. Connection Pool Tuning
-
maximumPoolSize
β How many connections at max -
minimumIdle
β How many idle connections to keep ready -
idleTimeout
β How long idle connections can live -
connectionTimeout
β Max time to wait for a connection
π Example: If your app gets 100 concurrent requests but pool size is 10, then 90 have to wait.
π§ c. Idle Connection Management
- Pool may shrink during low traffic (minIdle)
- Pool grows back when traffic increases
- This avoids keeping unused connections open
E.g.:
Pool size = 10
API idle = no traffic
-> Shrinks to 2 (minimumIdle)
New request comes
-> Expands to 10 again
π§ d. Transactions
Connections are tightly linked to transactions.
-
@Transactional
ensures:- One connection per transaction
- Auto commit or rollback
- Returned to pool after transaction ends
@Transactional
public void updateBalance(int userId, double amount) {
// single connection used here
userRepo.updateAmount(userId, amount);
}
π§ e. Common Mistakes to Avoid
- β Closing
DataSource
manually - β Holding connections too long
- β Not releasing connections in custom JDBC code
- β Using too small or too big pool size
- β Mixing DriverManager and HikariCP
π 7. Best Practice Summary
Approach | Level | Suitable For | Pros | Cons |
---|---|---|---|---|
Raw JDBC | 1 | Learning | Simple, transparent | No pooling, hard to scale |
DataSource (no pool) | 2 | Small apps | Cleaner code | Still no pooling |
HikariCP (with JdbcTemplate) | 3 | Production APIs, Services | Fast, efficient, reliable | Slight config needed |
JPA / Hibernate + HikariCP | 4 | Large apps, microservices | Clean, high-level abstraction | Learning curve, ORM overhead |
β
Recommendation:
For 95% of real Spring Boot projects:
π Use HikariCP + Spring Data (JPA or JdbcTemplate).
π§ͺ 8. Real-World Example: REST API with DB
User hits API β Spring Controller
β Service Layer
β Repository Layer (JPA or JdbcTemplate)
β Borrow Connection from Hikari Pool
β Execute Query
β Return Connection to Pool
β Return Response
β Fast, efficient, production ready.
π 9. Sample Project Structure
src/
ββ config/
β ββ DbConfig.java
ββ entity/
β ββ User.java
ββ repository/
β ββ UserRepository.java
ββ service/
β ββ UserService.java
ββ controller/
β ββ UserController.java
ββ application.properties
π§ 10. Monitoring & Troubleshooting
You can monitor the pool by:
- HikariCP metrics (via actuator)
- Prometheus / Grafana dashboards
- Logs (
spring.datasource.hikari.pool-name
)
Example Log:
HikariPool-1 - Pool stats (total=10, active=2, idle=8, waiting=0)
π Conclusion
- Start with JDBC to understand fundamentals π§
- Use
DataSource
to simplify connection creation π§© - Use
HikariCP
to handle real-world traffic efficiently β‘ - Use
JPA
orJdbcTemplate
for cleaner code β¨ - Monitor and tune pool to match your appβs needs π
Top comments (0)