How Spring Boot Creates DataSource and Connection Objects and Provides Them to Your Application

Understanding how Spring Boot automatically creates and manages database connections is very important for Spring Boot developers.

Spring Boot uses Auto Configuration + Connection Pooling + Dependency Injection to create and provide DataSource and Connection objects.

1. High-Level Flow

application.properties
        │
        ▼
Spring Boot Auto Configuration
        │
        ▼
Creates DataSource Bean
        │
        ▼
Connection Pool (HikariCP)
        │
        ▼
Connections created and managed
        │
        ▼
Spring injects DataSource into your code
        │
        ▼
You call getConnection()

2. Step 1 — You Define Database Properties

spring.datasource.url=jdbc:mysql://localhost:3306/employees
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

3. Step 2 — Spring Boot Auto Configuration

Spring Boot has an internal class:

DataSourceAutoConfiguration

Auto configuration class:

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

4. Step 3 — Spring Boot Chooses Connection Pool

PriorityConnection Pool
1HikariCP (default)
2Tomcat JDBC
3Commons DBCP

5. Step 4 — DataSource Bean Creation

@Bean
public DataSource dataSource() {
    HikariDataSource ds = new HikariDataSource();

    ds.setJdbcUrl("jdbc:mysql://localhost:3306/employees");
    ds.setUsername("root");
    ds.setPassword("root");

    return ds;
}

Normally you do not write this code. Spring Boot generates it automatically.

6. Step 5 — Connection Pool Creates Connections

Connection Pool (HikariCP)

+----------------------+
| Connection 1         |
| Connection 2         |
| Connection 3         |
| Connection 4         |
| Connection 5         |
+----------------------+

7. Step 6 — Spring Injects DataSource

@Service
public class EmployeeService {

    @Autowired
    private DataSource dataSource;

}

8. Step 7 — Getting Connection Object

Connection connection = dataSource.getConnection();
@Service
public class EmployeeService {

    @Autowired
    private DataSource dataSource;

    public void testConnection() throws Exception {

        Connection conn = dataSource.getConnection();

        System.out.println(conn);

        conn.close();
    }
}

Important: conn.close() does NOT close the real connection. It returns the connection to the pool.

9. Internal Working Diagram

Spring Boot Application
        │
        ▼
application.properties
        │
        ▼
DataSourceAutoConfiguration
        │
        ▼
HikariDataSource Bean
        │
        ▼
Hikari Connection Pool
        ┌──────────────────┐
        │ Connection 1     │
        │ Connection 2     │
        │ Connection 3     │
        │ Connection 4     │
        │ Connection 5     │
        └──────────────────┘
        │
        ▼
Injected into Beans
        │
        ▼
dataSource.getConnection()
        │
        ▼
Database

10. What Happens When getConnection() is Called

1 → Request goes to HikariDataSource
2 → Hikari checks pool
3 → Available connection returned
4 → Your application uses it
5 → conn.close()
6 → Returned back to pool

11. Without Spring Boot (Traditional Java)

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/employees");
config.setUsername("root");
config.setPassword("root");

HikariDataSource ds = new HikariDataSource(config);

Connection conn = ds.getConnection();

12. Important Classes Involved

ComponentClass
Auto ConfigurationDataSourceAutoConfiguration
Properties BindingDataSourceProperties
PoolHikariDataSource
Connectionjava.sql.Connection

13. Key Takeaways


Additional Section: How Connections Work When Using Spring Data JPA (JpaRepository)

1. High-Level Flow with JPA Repository

Controller
    │
    ▼
Service
    │
    ▼
JpaRepository
    │
    ▼
Spring Data JPA
    │
    ▼
EntityManager
    │
    ▼
Hibernate (JPA Provider)
    │
    ▼
DataSource
    │
    ▼
Connection Pool (HikariCP)
    │
    ▼
Database

2. Example Entity

@Entity
@Table(name="employees")
public class Employee {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

}

3. Repository Example

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {

}

4. Service Layer

@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository repository;

    public Employee save(Employee emp){
        return repository.save(emp);
    }

}

5. What Happens Internally When repository.save() Runs

repository.save(employee)
        │
        ▼
Spring Data JPA Proxy
        │
        ▼
EntityManager.persist()
        │
        ▼
Hibernate
        │
        ▼
DataSource.getConnection()
        │
        ▼
HikariCP Connection Pool
        │
        ▼
Database

6. Internal Working Diagram

Spring Boot Application
        │
        ▼
Spring Data JPA Repository
        │
        ▼
Proxy Implementation
        │
        ▼
EntityManager
        │
        ▼
Hibernate
        │
        ▼
DataSource
        │
        ▼
Hikari Connection Pool
        │
        ▼
Database

7. Important Classes Involved

LayerClass
RepositorySimpleJpaRepository
JPA APIEntityManager
ORMHibernate
ConnectionDataSource
PoolHikariDataSource

8. Key Idea

JpaRepository
     ↓
EntityManager
     ↓
Hibernate
     ↓
DataSource
     ↓
Connection Pool
     ↓
Database

Difference Between Traditional JDBC Connection and Spring Data JPA Repository

1. High-Level Architecture Comparison

Traditional JDBC Flow

Application Code
       │
       ▼
   JDBC API
       │
       ▼
DriverManager / DataSource
       │
       ▼
   JDBC Driver
       │
       ▼
    Database

Spring Data JPA Flow

Application Code
       │
       ▼
JpaRepository
       │
       ▼
Spring Data JPA
       │
       ▼
EntityManager
       │
       ▼
Hibernate (ORM)
       │
       ▼
DataSource (HikariCP)
       │
       ▼
Database

2. Example: Traditional JDBC

import java.sql.*;

public class EmployeeDAO {

    public void saveEmployee() throws Exception {

        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/test",
                "root",
                "root");

        String sql = "insert into employees(name) values (?)";

        PreparedStatement ps = conn.prepareStatement(sql);

        ps.setString(1, "John");

        ps.executeUpdate();

        ps.close();
        conn.close();
    }
}

3. Example: Spring Data JPA Repository

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {

}
@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository repository;

    public Employee save(Employee emp){
        return repository.save(emp);
    }
}

4. Key Differences

FeatureTraditional JDBCSpring Data JPA
LevelLow levelHigh level ORM
SQL WritingManualUsually automatic
Connection HandlingManualAutomatic
Boilerplate CodeLargeVery small
MappingManual ResultSet mappingAutomatic Entity mapping
TransactionsManualManaged by Spring
Development SpeedSlowVery fast
MaintainabilityHardEasy

5. Data Mapping Example

JDBC Mapping

Employee emp = new Employee();

emp.setId(rs.getLong("id"));
emp.setName(rs.getString("name"));

JPA Mapping

@Entity
public class Employee {

    @Id
    private Long id;

    private String name;
}

6. Transaction Handling

JDBC

conn.setAutoCommit(false);
conn.commit();
conn.rollback();

JPA

@Transactional
public void saveEmployee(Employee emp){
    repository.save(emp);
}

7. Final Concept Diagram

Traditional JDBC

Application
   │
   ▼
JDBC API
   │
   ▼
SQL + Connection Handling
   │
   ▼
Database

Spring Data JPA

Application
   │
   ▼
JpaRepository
   │
   ▼
EntityManager
   │
   ▼
Hibernate ORM
   │
   ▼
Connection Pool
   │
   ▼
Database