Spring Data JPA in Practice — Repository · N+1 · DTO Mapping
Spring Data JPA in Practice — Repository · N+1 · DTO Mapping
🎯 What you'll be able to do after this lesson
After finishing this lesson, you'll be able to confidently do the following three things.
- ▸✅ Implement full CRUD with zero lines of code by simply extending JpaRepository
- ▸✅ Solve the N+1 problem using @EntityGraph or JOIN FETCH
- ▸✅ Understand Lazy vs Eager loading — and why real-world code always uses Lazy
Keep these goals as a checklist, and close the lesson once you can answer all of them.
JpaRepository — *Just name the method and you're done*
The biggest magic trick
Declare just one interface line — and Spring auto-generates the implementation at runtime. Methods available immediately:
- ▸
save(entity)— INSERT or UPDATE - ▸
findById(id)— returns Optional - ▸
findAll()— fetch all records - ▸
count()— count records - ▸
deleteById(id)— delete a record - ▸
existsById(id)— check existence
Generating queries from method names
Follow the method naming rules and Spring generates the SQL automatically. A clear win for both readability and performance.
Keywords: findBy, countBy, existsBy, deleteBy + field name + (Containing, GreaterThan, In, Between, OrderBy...Asc/Desc ...)
Writing JPQL directly — @Query
For complex queries, write them in JPQL (Java Persistence Query Language):
JPQL looks similar to SQL, but is written using entity names — not table names.
Pagination — Pageable
Infinite scroll and page navigation are both handled with this.
The N+1 Problem — The most common trap in production
The scenario
100 users → 101 queries. Performance degrades exponentially as data grows. This is the N+1 problem.
Solution 1 — @EntityGraph (simplest)
Resolved in a single JOIN query. In SQL:
Solution 2 — JOIN FETCH (manual JPQL)
DISTINCT matters — without it, you get duplicate rows.
Solution 3 — Batch Size (@BatchSize)
Not a complete fix, but reduces N+1 to N/batchSize+1. Useful when dealing with multiple associations combined with pagination.
Lazy vs Eager — When to use which
Production rule: always LAZY. EAGER is the root cause of unpredictable query explosions. Use @EntityGraph or JOIN FETCH on demand when you need eager behavior.
Debugging N+1 — turn on show-sql
During development, actual SQL is printed to the console. If the same query repeats dozens of times, that's a red flag for N+1.
Entity → DTO Mapping — *Why you must keep them separate*
Why you must not return an Entity directly
Four problems:
1. Circular reference: Bidirectional mapping between User ↔ Order causes infinite JSON serialization → StackOverflow.
2. Sensitive data exposure: Fields like password and internalNote get exposed automatically.
3. Coupling API schema to DB schema: Renaming a DB column breaks the API too.
4. Unnecessary queries: Jackson tries to serialize Lazy fields, triggering extra queries.
The DTO pattern
The static factory method (from) owns the mapping responsibility — keeping the Entity and DTO unaware of each other.
Separate DTOs for input as well
@Valid automatically runs Bean Validation (@Email, @NotBlank, @Size). On validation failure, a 400 Bad Request is returned automatically.
MapStruct — Auto-generate mapping code
As the number of DTOs grows, so does the number of from() methods. MapStruct generates mapping code at compile time — eliminating boilerplate.
The standard approach for medium-to-large projects. Start by writing it manually, then introduce MapStruct once you're comfortable.
🤖 Try asking AI like this
Knowing the concepts in this lesson lets you give specific instructions to AI. Not a vague 'fix this' — but a vocabulary-driven request. That's where token savings begin.
- ▸'This findAll + loop is causing N+1 — fix it with @EntityGraph'
- ▸'Add a static factory method that converts this Entity to a UserResponse DTO'
- ▸'Add a findByEmailAndActive method signature to JpaRepository'
Why this reduces tokens
Without understanding the concept, you receive an AI answer and still have to ask 'What does that mean?' again. That follow-up question is what consumes tokens. Learn the concept once, and the conversation ends in one turn.