How I Improved Spring Boot Performance by 30% at WageNest
•6 min read•Yaswanth Reddy Koduru
Spring BootPerformanceJPAHibernateOptimization
How I Improved Spring Boot Performance by 30% at WageNest
At WageNest, our payroll processing system was handling increasing transaction volumes, but response times were creeping up. After profiling and optimization, we achieved a 25-30% performance improvement. Here's how.
The Performance Problem
Our Spring Boot microservices were showing:
- API response times averaging 800-1200ms
- Database connection pool exhaustion during peak hours
- Slow JPA queries with N+1 problems
- Redis cache misses on frequently accessed data
For a payroll system processing thousands of transactions daily, this wasn't acceptable.
Optimization Strategy
1. JPA/Hibernate Query Optimization
Problem: N+1 queries were killing performance.
Solution:
// Before: N+1 query problem
@OneToMany(mappedBy = "employee")
private List<PayrollTransaction> transactions;
// After: Eager fetch with JOIN FETCH
@Query("SELECT e FROM Employee e " +
"JOIN FETCH e.transactions " +
"WHERE e.tenantId = :tenantId")
List<Employee> findAllWithTransactions(@Param("tenantId") Long tenantId);
We also added:
- Entity graphs for complex joins
- Batch fetching where appropriate
- Query hints for optimizer guidance
2. Database Indexing
Created composite indexes on frequently queried columns:
CREATE INDEX idx_payroll_tenant_date
ON payroll_transactions(tenant_id, process_date, status);
CREATE INDEX idx_employee_tenant_active
ON employees(tenant_id, is_active);
3. Redis Caching Strategy
Implemented multi-level caching:
@Cacheable(value = "employees", key = "#tenantId + '-' + #employeeId")
public Employee getEmployee(Long tenantId, Long employeeId) {
return employeeRepository.findById(employeeId);
}
@CacheEvict(value = "employees", key = "#tenantId + '-' + #employee.id")
public Employee updateEmployee(Long tenantId, Employee employee) {
return employeeRepository.save(employee);
}
4. Connection Pool Tuning
Optimized HikariCP configuration:
spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
Results
After optimization:
- Average API response time: 300-500ms (60% improvement)
- Database connection pool utilization: 40% (down from 95%)
- Cache hit rate: 85%
- Throughput: +40% transactions per second
Key Takeaways
- Profile before optimizing - Use Spring Boot Actuator + Micrometer
- N+1 queries are everywhere - Always use JOIN FETCH
- Indexes matter - Composite indexes for multi-column queries
- Cache strategically - Not everything needs caching
- Monitor continuously - Performance degrades over time
Building high-performance Spring Boot systems? Let's discuss optimization strategies.