Thursday, 17 July 2025

Solving the N+1 Query Problem in REST APIs: A Real-World Banking Example (Made Easy for Spring Boot Developers)

If you're using Spring Boot with Hibernate (JPA) and a relational database like MySQL/PostgreSQL, the N+1 Query Problem can silently hurt your API performance.

Let’s understand this issue in simple steps using a real-world banking project example, and how to fix it using Spring Boot tricks.


๐Ÿ“Œ What is the N+1 Problem?

The N+1 problem occurs when:

  • 1 SQL query fetches the main (parent) data — for example, bank accounts.

  • Then N additional SQL queries are executed for related (child) data — like each account’s transactions.

Expected: 1 smart query to fetch everything. ❌ Actual: 1 query for accounts + N queries for transactions = N+1 total queries.

This increases database load and slows down your REST APIs.


๐Ÿฆ Spring Boot Banking API Example

Say you build a banking dashboard endpoint:

@GetMapping("/api/accounts")
public List<AccountDTO> getAllAccounts() {
    List<Account> accounts = accountRepository.findAll();
    return accounts.stream()
        .map(account -> new AccountDTO(account.getId(), account.getTransactions()))
        .collect(Collectors.toList());
}

Behind the scenes:

  • findAll() runs: SELECT * FROM account;

  • Then for each account, Hibernate runs: SELECT * FROM transaction WHERE account_id = ?;

➡️ With 100 accounts, this results in 101 queries. That’s the N+1 problem.


Why Is It a Big Deal?

  • ๐Ÿšซ Bad for performance: 100 queries slow down response time.

  • ๐Ÿ”ฅ Heavy DB load: Affects scaling when users grow.

  • ๐Ÿงช Hard to debug: Looks fine in code, but performs poorly in production.


How to Fix N+1 in Spring Boot (Step-by-Step)

✅ 1. Use JOIN FETCH in JPA Query

@Query("SELECT a FROM Account a JOIN FETCH a.transactions")
List<Account> findAllWithTransactions();

✅ Fetches everything in 1 query.

✅ 2. Use JPA Entity Graphs

@EntityGraph(attributePaths = {"transactions"})
List<Account> findAll();

✅ Cleaner and better for dynamic loading.

✅ 3. Use DTO Projection (Recommended for REST)

@Query("SELECT new com.bank.dto.AccountDTO(a.id, t) 
FROM Account a JOIN a.transactions t")
List<AccountDTO> getAccountDTOs();

✅ Loads only the required data — no extra queries.

✅ 4. Use Batch Fetching (Optional)

In application.properties:

spring.jpa.properties.hibernate.default_batch_fetch_size=100

✅ Tells Hibernate to fetch child records in batches.


๐Ÿ’ก Best Practices & Tricky Interview Points

  • ๐Ÿงต Lazy vs Eager:

    • Use LAZY loading to avoid unnecessary data.

    • Use JOIN FETCH when you really need the related data.

  • ๐Ÿ›ก️ Avoid LazyInitializationException:

    • Use @Transactional in service layer if accessing lazy fields.

  • ๐Ÿงช Testing:

    • Use Hibernate query counters in tests to catch N+1 bugs.

    • Enable SQL logging: spring.jpa.show-sql=true

  • ๐Ÿง  Interview Tip:

    • Be ready to explain how you identify and fix N+1 using Spring Boot tools.


๐Ÿš€ Summary: Fixing N+1 in Spring Boot

Problem Fix
Too many queries Use JOIN FETCH
Lazy loading issues Use EntityGraph or @Transactional
Poor API performance Use DTO projections
Query explosion Use batch fetch settings

๐Ÿง  Final Thought

"The fastest code isn’t the one that runs first — it’s the one that hits the DB the least.”

If you're building REST APIs for enterprise, finance, or dashboards — fixing N+1 makes your system faster, lighter, and scalable.

Happy Learning :) 


Sunday, 13 July 2025

JWT Interview Q & A asked in MNC company

 

๐Ÿ” 1. How does Spring Security integrate with JWT-based authentication?

Answer:
Spring Security provides a flexible filter chain where you can plug in your own OncePerRequestFilter (e.g., JwtAuthenticationFilter) to intercept incoming requests and:

  • Extract the JWT from the Authorization header

  • Validate it

  • Set the Authentication object in SecurityContextHolder

➡️ This allows stateless authentication using JWT.


๐Ÿ” 2. Why do we use OncePerRequestFilter in JWT security setup?

Answer:
OncePerRequestFilter ensures your filter runs only once per request, making it ideal for:

  • Checking JWT

  • Verifying token signature

  • Setting authentication context

If used wrongly, it can cause repeated token processing.


๐Ÿ” 3. Can we disable session creation in Spring Security for JWT?

Answer:
Yes. JWT is stateless, so we must disable session creation:


http.sessionManagement()

    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);


Without this, Spring may still create sessions and defeat the purpose of using JWT.


๐Ÿ” 4. Where do you validate the JWT token in Spring Boot?

Answer:
In a custom JWT filter, before the request reaches the controller:

  • You extract the token from Authorization header

  • Validate the signature and expiration

  • Fetch user details (optional)

  • Set Authentication in SecurityContext


๐Ÿ” 5. What happens if the JWT token is expired?

Answer:
When a JWT token is expired, it throws a specific exception — most commonly:


io.jsonwebtoken.ExpiredJwtException


In your custom JWT filter (usually extending OncePerRequestFilter), you should catch this exception and return a proper HTTP response:


try {

    // validate token logic

} catch (ExpiredJwtException e) {

    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

    response.getWriter().write("Token expired. Please login again or use refresh token.");

    return;

}


๐Ÿ“Œ HTTP Response:


401 Unauthorized  

Body: Token expired. Please login again or use refresh token.


๐Ÿ”„ Best Practice: Use a refresh token mechanism so that expired tokens can be refreshed without forcing the user to re-login every time.


๐Ÿ” 6. How do you handle JWT in microservices architecture with Spring Security?

Answer:
In microservices, the best approach is to delegate all authentication to a central Auth Service. Here's the flow:

  1. User logs in via Auth Service → receives access token and refresh token.

  2. Access token is then passed in the Authorization: Bearer <token> header for every request to other services.

  3. Each service:

    • Validates the token using a shared secret or public key (if using asymmetric signing like RS256).

    • Authorizes the request based on roles in token claims.

  4. No session state is stored; each service is stateless.

Optional best practice:

  • Use Spring Cloud Gateway or an API Gateway to centralize token validation so individual services don't have to repeat it.


๐Ÿ” 7. Is it safe to keep user roles in JWT?

Answer:
Yes — if the JWT is signed properly using a secure algorithm (HS256, RS256) and a strong secret/private key.

You can embed roles in the JWT payload like this:


{

  "sub": "user1",

  "roles": ["ROLE_ADMIN", "ROLE_USER"],

  "exp": 1723489234

}


๐Ÿ“Œ In your Spring Boot filter, you extract these roles and convert them to GrantedAuthority:


UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(

    username, null, authoritiesFromToken

);


⚠️ Do not trust claims blindly if the signature is invalid or token is tampered.

✅ Signed tokens = safe to use for roles
❌ Unsigned (alg: none) or weak key = huge security risk


๐Ÿ” 8. What is the best way to store JWT tokens on the frontend?

Answer:

  • Access token: HttpOnly Secure Cookie (to avoid XSS)

  • Refresh token: also in HttpOnly cookie or encrypted local storage

❌ Avoid storing in localStorage or sessionStorage — vulnerable to XSS attacks.


๐Ÿ” 9. Can we use Spring Security with both Session and JWT?

Answer:
Not advisable. Choose one:

  • Use Session + CSRF for monoliths or UI-driven apps

  • Use JWT (stateless) for REST APIs and microservices

Mixing both often leads to confusion and security holes.


๐Ÿ” 10. How do you implement role-based access with JWT + Spring Security?

Answer:

  1. Encode roles into JWT claims.

  2. In your filter, extract and set GrantedAuthority in Authentication.

  3. Then use:

@PreAuthorize("hasRole('ADMIN')")


or


http.authorizeHttpRequests().requestMatchers("/admin/**").hasRole("ADMIN")


✅ Don’t forget to prefix roles with "ROLE_".