<< All versions
Skill v1.0.0
Automated scandiegosouzapw/awesome-omni-skill/spring-boot-performance-ductringuyen0186
──Details
PublishedMarch 6, 2026 at 01:14 PM
Content Hashsha256:e3b0c44298fc1c14...
Git SHAdiscovery:3d
──Files
Files (1 file, 8.0 KB)
SKILL.md8.0 KBactive
SKILL.md · 311 lines · 8.0 KB
version: "1.0.0" name: spring-boot-performance description: Guide for optimizing Spring Boot application performance including caching, pagination, async processing, and JPA optimization. Use this when addressing performance issues or implementing high-traffic features.
Spring Boot Performance Optimization
Follow these practices to optimize application performance.
Pagination for Large Datasets
NEVER load entire tables into memory:
java
// ❌ WRONG - Can cause OutOfMemoryErrorList<User> allUsers = userRepository.findAll();// ✅ CORRECT - Use pagination@GetMapping("/users")public Page<UserDTO> getUsers(@RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "20") int size,@RequestParam(defaultValue = "id") String sortBy) {Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy));return userRepository.findAll(pageable).map(userMapper::toDto);}
Projections for Partial Data
Use projections when you don't need full entities:
java
// Interface projectionpublic interface UserSummary {Long getId();String getName();String getEmail();}@Repositorypublic interface UserRepository extends JpaRepository<User, Long> {List<UserSummary> findAllProjectedBy();@Query("SELECT u.id as id, u.name as name FROM User u")List<UserSummary> findUserSummaries();}
Avoiding N+1 Query Problem
java
// ❌ WRONG - N+1 queriesList<Order> orders = orderRepository.findAll();for (Order order : orders) {// This causes N additional queriesList<OrderItem> items = order.getItems();}// ✅ CORRECT - Use JOIN FETCH@Repositorypublic interface OrderRepository extends JpaRepository<Order, Long> {@Query("SELECT o FROM Order o LEFT JOIN FETCH o.items")List<Order> findAllWithItems();@EntityGraph(attributePaths = {"items", "customer"})List<Order> findAll();}
Caching Configuration
java
@Configuration@EnableCachingpublic class CacheConfig {@Beanpublic CacheManager cacheManager() {CaffeineCacheManager cacheManager = new CaffeineCacheManager();cacheManager.setCaffeine(Caffeine.newBuilder().maximumSize(1000).expireAfterWrite(Duration.ofMinutes(10)).recordStats());return cacheManager;}}@Servicepublic class ServiceTypeService {@Cacheable(value = "serviceTypes", key = "#id")public ServiceType getServiceType(Long id) {return serviceTypeRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Service type not found"));}@CacheEvict(value = "serviceTypes", key = "#serviceType.id")public ServiceType updateServiceType(ServiceType serviceType) {return serviceTypeRepository.save(serviceType);}@CacheEvict(value = "serviceTypes", allEntries = true)public void clearCache() {// Clears entire cache}}
Async Processing
java
@Configuration@EnableAsyncpublic class AsyncConfig {@Bean(name = "taskExecutor")public Executor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(25);executor.setThreadNamePrefix("Async-");executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}}@Servicepublic class NotificationService {@Async("taskExecutor")public CompletableFuture<Void> sendEmailNotification(String email, String message) {// Long-running email sending operation// This runs in a separate threadreturn CompletableFuture.completedFuture(null);}}// Usage in controller@PostMapping("/appointments")public AppointmentDTO createAppointment(@RequestBody AppointmentRequest request) {AppointmentDTO appointment = appointmentService.create(request);// Fire and forget - doesn't block responsenotificationService.sendEmailNotification(appointment.getCustomerEmail(),"Your appointment is confirmed");return appointment;}
Connection Pool Configuration
yaml
# application.ymlspring:datasource:hikari:maximum-pool-size: 10minimum-idle: 5idle-timeout: 30000connection-timeout: 20000max-lifetime: 1800000pool-name: SalonHubPool
JPA Optimization
yaml
# application.ymlspring:jpa:properties:hibernate:# Batch processingjdbc:batch_size: 50order_inserts: trueorder_updates: true# Second-level cache (optional)cache:use_second_level_cache: trueregion:factory_class: org.hibernate.cache.jcache.JCacheRegionFactory# Query hintsdefault_batch_fetch_size: 25
Batch Processing
java
@Service@Transactionalpublic class BulkImportService {@PersistenceContextprivate EntityManager entityManager;public void bulkInsert(List<Customer> customers) {int batchSize = 50;for (int i = 0; i < customers.size(); i++) {entityManager.persist(customers.get(i));if (i > 0 && i % batchSize == 0) {entityManager.flush();entityManager.clear();}}entityManager.flush();entityManager.clear();}}
Lazy Loading Best Practices
java
@Entitypublic class Order {@Idprivate Long id;// Lazy by default for collections@OneToMany(mappedBy = "order", fetch = FetchType.LAZY)private List<OrderItem> items;// Consider lazy for large objects@Basic(fetch = FetchType.LAZY)@Lobprivate String description;}// Initialize lazy collections when needed@Transactional(readOnly = true)public Order getOrderWithItems(Long id) {Order order = orderRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Order not found"));// Force initialization within transactionHibernate.initialize(order.getItems());return order;}
Response Compression
yaml
# application.ymlserver:compression:enabled: truemime-types: application/json,application/xml,text/html,text/xml,text/plainmin-response-size: 1024
Index Optimization
sql
-- Create indexes for frequently queried columnsCREATE INDEX idx_appointments_customer_id ON appointments(customer_id);CREATE INDEX idx_appointments_employee_id ON appointments(employee_id);CREATE INDEX idx_appointments_date ON appointments(appointment_time);-- Composite index for common query patternsCREATE INDEX idx_appointments_status_date ON appointments(status, appointment_time);
Performance Monitoring
java
@Aspect@Componentpublic class PerformanceLoggingAspect {private static final Logger logger = LoggerFactory.getLogger(PerformanceLoggingAspect.class);@Around("@annotation(LogExecutionTime)")public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {long start = System.currentTimeMillis();Object result = joinPoint.proceed();long duration = System.currentTimeMillis() - start;logger.info("{} executed in {} ms", joinPoint.getSignature(), duration);return result;}}@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface LogExecutionTime {}
Performance Checklist
- [ ] Use pagination for all list endpoints
- [ ] Implement caching for frequently accessed, rarely changed data
- [ ] Check for N+1 queries using logging or profiler
- [ ] Use projections when full entities aren't needed
- [ ] Add database indexes for frequently queried columns
- [ ] Configure connection pooling appropriately
- [ ] Use async processing for non-critical operations
- [ ] Enable response compression
- [ ] Monitor slow queries and optimize