Bean Circular Dependency in Spring
What is it?
When two beans depend on each other — neither can be created first.
Bean A needs B → Bean B needs A → 💥
Spring throws: BeanCurrentlyInCreationException:
Requested bean is currently in creation:
Is there an unresolvable circular reference?
3 ways to fix:
1. @Lazy ✅ recommended
Delays bean creation until actually needed — breaks the cycle.
2. Setter Injection
Spring creates both beans first, injects after.
3. Redesign — best long term
Extract shared logic into a third bean. Circular dependency usually signals an architecture problem.
#Java #Spring #Beans #CircularDependency
What is it?
When two beans depend on each other — neither can be created first.
Bean A needs B → Bean B needs A → 💥
Spring throws: BeanCurrentlyInCreationException:
Requested bean is currently in creation:
Is there an unresolvable circular reference?
3 ways to fix:
1. @Lazy ✅ recommended
@Component
public class A {
public A(@Lazy B b) { }
}
Delays bean creation until actually needed — breaks the cycle.
2. Setter Injection
@Autowired
public void setB(B b) { this.b = b; }
Spring creates both beans first, injects after.
3. Redesign — best long term
Extract shared logic into a third bean. Circular dependency usually signals an architecture problem.
#Java #Spring #Beans #CircularDependency
❤1
@Value in Spring
What is it?
Injects values from properties files or expressions directly into fields at runtime.
1. From properties file ${}
2. SpEL expressions #{}
Key difference:
${} reads from properties files
#{} evaluates Java expressions at runtime
#Java #Spring #Value #SpEL #Properties
What is it?
Injects values from properties files or expressions directly into fields at runtime.
1. From properties file ${}
application.yml
app.servers=server1,server2,server3
app.timeout=5000
@Value("${app.servers}")
private String[] servers;
@Value("${app.timeout:5000}") // default if not found
private int timeout;2. SpEL expressions #{}
@Value("#{2 * 3}") // math → 6
private int result;
@Value("#{userService.getDefaultName()}") // method call on a bean
private String name;
@Value("#{T(Math).PI}") // static field
private double pi;Key difference:
${} reads from properties files
#{} evaluates Java expressions at runtime
#Java #Spring #Value #SpEL #Properties
Java 21 Virtual Threads
https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html#GUID-DC4306FC-D6C1-4BCC-AECE-48C32C1A8DAA
#virtual_threads #java_21 #java
https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html#GUID-DC4306FC-D6C1-4BCC-AECE-48C32C1A8DAA
#virtual_threads #java_21 #java
Oracle Help Center
Core Libraries
Virtual threads are lightweight threads that reduce the effort of writing, maintaining, and debugging high-throughput concurrent applications.
How JVM Works Internally?
First, we create a .java file, then compile it with javac MyApp.java, which produces a .class file containing bytecode.
#JVM #heap #stack #meta_space #native #pc_register #class_loader #boostrap #extension #application #GC #minor_gc #major_gc #eden
First, we create a .java file, then compile it with javac MyApp.java, which produces a .class file containing bytecode.
After that, the ClassLoader starts working. It follows the Parent Delegation Model — so the request goes upward first, not downward. The Application ClassLoader (where our class data is located) delegates to Extension (extra libraries for helping Java), which delegates to Bootstrap (Java core libraries like java.lang, java.util). Bootstrap tries to load the class first. If it can't find it, the request falls back to Extension, and finally to Application. This prevents malicious code from replacing core Java classes.
After finishing this process, data gets stored in 5 types of memory according to their purpose: Heap (for objects, reference types), Stack (references, primitive types, method frames), Method Area (class metadata, static fields, method bytecode), Native Method Stack (for non-Java code called through JNI), and PC Register (holds the address of the current bytecode instruction for each thread — needed for thread switching).
After all that, the Execution Engine starts working. It has 2 modes working simultaneously. The Interpreter reads bytecode instruction by instruction. While it runs, the JVM counts how many times each method is called. After a method is called around 10,000 times, it becomes "hot code" and the JIT Compiler converts it into native machine code (0s and 1s). From that point, that method runs directly as compiled code, skipping the Interpreter. This is why Java gets faster over time.
Here also GC works, which manages Heap memory by removing unreachable objects. It has Young Generation — new objects come to Eden, and after surviving Minor GC cycles they get copied between Survivor1 and Survivor2 (one is always empty). After around 15 cycles they move to Old Generation, where objects are less likely to be removed and can be cleaned by Major GC or Full GC.
#JVM #heap #stack #meta_space #native #pc_register #class_loader #boostrap #extension #application #GC #minor_gc #major_gc #eden
Why the program slow down over time?
There might be several reasons why a Java application slows down over time.
#memory_leak #gc_pressure #thread_contention #JIT_Decomposition #Resource_Exhaustion
There might be several reasons why a Java application slows down over time.
1. Memory Leak — objects that are no longer needed still have references pointing to them, so GC can't remove them. For example, adding objects to a static List and never clearing it. The Heap gradually fills up, GC runs more and more frequently, recovers almost nothing, and the application slows down. In the worst case, if GC spends more than 98% of CPU time and recovers less than 2% of the Heap, the JVM throws OutOfMemoryError: GC overhead limit exceeded.
2. GC Pressure — even without a leak, if your application creates too many short-lived objects too fast, Minor GC runs constantly. And if many objects survive long enough to reach Old Generation, Full GC kicks in — which is a stop-the-world pause that freezes the entire application.
3. Thread Contention — when multiple threads compete for the same lock or synchronized block, they wait instead of working. The application has available CPU cores but threads are stuck in a queue, so throughput drops.
4. JIT Decoptimisation — the JIT Compiler makes assumptions when optimising hot code. If those assumptions become invalid later (for example, a new subclass appears), the JIT throws away the compiled code and falls back to the Interpreter. This causes temporary performance drops.
5. Resource Exhaustion — unclosed connections, streams, or file handles accumulate over time. The application starts waiting for available resources instead of processing requests.
#memory_leak #gc_pressure #thread_contention #JIT_Decomposition #Resource_Exhaustion
Why JVM Doesn't Exit After main() Finishes?
JVM exits only when all non-daemon threads finish. If main() ends but other threads are still running — JVM stays alive.
Common culprits — infinite loop in a thread, ExecutorService not shut down, Timer or ScheduledExecutorService still running, unclosed DB or socket connections holding background threads.
Fix — make background threads daemon with setDaemon(true) so they die automatically when main dies, or properly shut down ExecutorService, or interrupt threads explicitly.
#Java #JVM #Threads #Daemon
JVM exits only when all non-daemon threads finish. If main() ends but other threads are still running — JVM stays alive.
Common culprits — infinite loop in a thread, ExecutorService not shut down, Timer or ScheduledExecutorService still running, unclosed DB or socket connections holding background threads.
Fix — make background threads daemon with setDaemon(true) so they die automatically when main dies, or properly shut down ExecutorService, or interrupt threads explicitly.
#Java #JVM #Threads #Daemon
What's the key differences between Java 8 vs Java 17?
GC — Java 8 defaults to Parallel GC (rare but long pauses). Java 9+ defaults to G1 (frequent but short pauses). Both do Full GC if memory leaks exist.
Strings — Java 8 stores every character as 2 bytes. Java 9+ stores Latin characters as 1 byte, falls back to 2 bytes for Cyrillic/Chinese. Automatic memory saving, zero code changes.
PermGen → Metaspace — Java 8 removed PermGen (fixed-size box for class metadata) and replaced it with Metaspace (grows dynamically using native memory). Old -XX:MaxPermSize flags silently ignored.
Reflection locked down — Java 9+ introduced the module system and restricted access to internal JDK classes like sun.misc.Unsafe. Java 9-15 showed warnings. Java 16+ throws hard errors. This broke Hibernate, Spring, and hundreds of libraries. Main reason companies stayed on Java 8 for years.
New language features — Records (one-line DTOs), sealed classes (controlled inheritance), pattern matching (no manual casting after instanceof), text blocks (multiline strings). None exist in Java 8.
JIT — Java 8 had C1 and C2 compilers separately. Java 9+ introduced tiered compilation by default — C1 compiles quickly first, C2 recompiles hot methods with deeper optimisations. Faster warm-up.
API additions — var for local variables (Java 10), new HttpClient (Java 11), helpful NullPointerException messages showing exactly which reference was null (Java 14), Stream.toList() shortcut (Java 16).
#java8 #java9+
GC — Java 8 defaults to Parallel GC (rare but long pauses). Java 9+ defaults to G1 (frequent but short pauses). Both do Full GC if memory leaks exist.
Strings — Java 8 stores every character as 2 bytes. Java 9+ stores Latin characters as 1 byte, falls back to 2 bytes for Cyrillic/Chinese. Automatic memory saving, zero code changes.
PermGen → Metaspace — Java 8 removed PermGen (fixed-size box for class metadata) and replaced it with Metaspace (grows dynamically using native memory). Old -XX:MaxPermSize flags silently ignored.
Reflection locked down — Java 9+ introduced the module system and restricted access to internal JDK classes like sun.misc.Unsafe. Java 9-15 showed warnings. Java 16+ throws hard errors. This broke Hibernate, Spring, and hundreds of libraries. Main reason companies stayed on Java 8 for years.
New language features — Records (one-line DTOs), sealed classes (controlled inheritance), pattern matching (no manual casting after instanceof), text blocks (multiline strings). None exist in Java 8.
JIT — Java 8 had C1 and C2 compilers separately. Java 9+ introduced tiered compilation by default — C1 compiles quickly first, C2 recompiles hot methods with deeper optimisations. Faster warm-up.
API additions — var for local variables (Java 10), new HttpClient (Java 11), helpful NullPointerException messages showing exactly which reference was null (Java 14), Stream.toList() shortcut (Java 16).
#java8 #java9+
What Happens if main() is Not Static
When you type java MyApp, the Heap is empty — no objects exist yet. The JVM needs an entry point to start your programme.
If main() were non-static — JVM would need to create an object first. But which constructor? What arguments? What if it throws an exception? JVM has no information to decide.
With static — JVM calls MyApp.main(args) directly on the class level. No object needed, no guessing.
Without static — JVM doesn't even try. You get:
Error: Main method not found, please define as public static void main(String[] args)
Java 21 introduced a preview feature — you can write just void main() without static, without String[] args, without public. JVM handles object creation internally.
#Java #JVM #Static #Main
When you type java MyApp, the Heap is empty — no objects exist yet. The JVM needs an entry point to start your programme.
If main() were non-static — JVM would need to create an object first. But which constructor? What arguments? What if it throws an exception? JVM has no information to decide.
With static — JVM calls MyApp.main(args) directly on the class level. No object needed, no guessing.
Without static — JVM doesn't even try. You get:
Error: Main method not found, please define as public static void main(String[] args)
Java 21 introduced a preview feature — you can write just void main() without static, without String[] args, without public. JVM handles object creation internally.
#Java #JVM #Static #Main
Memory Leaks in Java — yes, even with GC
A lot of devs think "Java has GC, so no memory leaks". I thought the same. Then I spent 3 hours debugging why our app crashed every night at 3am.
Turned out — one unclosed DB connection. That's it.
GC is smart but it's not magic. It removes objects nobody references anymore. The problem is you — you keep referencing objects you forgot about.
Classic examples from real life:
You register a listener and never unregister. You put something in ThreadLocal and move on. You cache objects in a static list and never clean it. You open a connection and "handle it later".
The app doesn't crash immediately. It slows down. Memory grows. GC works harder. Until one night — boom.
The fix isn't a library or a pattern. It's just discipline — close what you open.
#Java #Backend #RealTalk
A lot of devs think "Java has GC, so no memory leaks". I thought the same. Then I spent 3 hours debugging why our app crashed every night at 3am.
Turned out — one unclosed DB connection. That's it.
GC is smart but it's not magic. It removes objects nobody references anymore. The problem is you — you keep referencing objects you forgot about.
Classic examples from real life:
You register a listener and never unregister. You put something in ThreadLocal and move on. You cache objects in a static list and never clean it. You open a connection and "handle it later".
The app doesn't crash immediately. It slows down. Memory grows. GC works harder. Until one night — boom.
The fix isn't a library or a pattern. It's just discipline — close what you open.
#Java #Backend #RealTalk
GC Pauses Increased After a Small Code Change
A small code change caused GC pauses to spike. How?
Most developers add a log line, forget to close a connection, or switch from primitive to wrapper type. Looks innocent. But the chain reaction is brutal.
Too many objects created → Eden fills fast → Minor GC runs constantly → objects survive and get promoted to Old Generation → Old Gen fills up → Major GC kicks in → long Stop The World pause.
Minor GC pauses are short — milliseconds. Major GC pauses are long — hundreds of milliseconds or even seconds. That's the difference between a smooth app and one that freezes randomly.
The culprit is almost always objects living longer than they should — unclosed connections, unbounded caches, forgotten listeners.
#Java #JVM #GC #Performance
A small code change caused GC pauses to spike. How?
Most developers add a log line, forget to close a connection, or switch from primitive to wrapper type. Looks innocent. But the chain reaction is brutal.
Too many objects created → Eden fills fast → Minor GC runs constantly → objects survive and get promoted to Old Generation → Old Gen fills up → Major GC kicks in → long Stop The World pause.
Minor GC pauses are short — milliseconds. Major GC pauses are long — hundreds of milliseconds or even seconds. That's the difference between a smooth app and one that freezes randomly.
The culprit is almost always objects living longer than they should — unclosed connections, unbounded caches, forgotten listeners.
#Java #JVM #GC #Performance
Increasing Heap Size Made Performance Worse
Counterintuitive but real. Here's why.
Bigger heap means more objects can live in memory. GC runs less frequently — sounds good. But when Major GC finally kicks in it has to scan the entire heap.
512MB heap → Major GC → 200ms pause
16GB heap → Major GC → 10 second pause 💀
App doesn't crash. It just freezes for 10 seconds randomly. Users think it's dead.
More heap = less frequent but more painful GC pauses.
The real fix is not throwing more memory at the problem. Fix memory leaks first. Then if you still need large heap — switch to ZGC or Shenandoah which keep pauses under 1ms regardless of heap size.
#Java #JVM #GC #Performance #Heap
Counterintuitive but real. Here's why.
Bigger heap means more objects can live in memory. GC runs less frequently — sounds good. But when Major GC finally kicks in it has to scan the entire heap.
512MB heap → Major GC → 200ms pause
16GB heap → Major GC → 10 second pause 💀
App doesn't crash. It just freezes for 10 seconds randomly. Users think it's dead.
More heap = less frequent but more painful GC pauses.
The real fix is not throwing more memory at the problem. Fix memory leaks first. Then if you still need large heap — switch to ZGC or Shenandoah which keep pauses under 1ms regardless of heap size.
#Java #JVM #GC #Performance #Heap
== vs equals() in Java
== compares memory addresses — are these two variables pointing to the same object in heap?
equals() compares content — are these two objects meaningfully the same?
Default equals() from Object class just does ==. The magic happens when you override it — like String does, comparing character by character.
Two Dogs with the same name are two different objects at different heap addresses. == returns false. Override equals() and it returns true.
Important rule — whenever you override equals() always override hashCode() too. Otherwise HashMap and HashSet break completely.
#Java #CoreJava #Equals #Hashcode
Shallow Copy vs Deep Copy
Shallow copy — copies the object but nested objects are still shared. Change a nested object in the copy and the original changes too.
Deep copy — copies everything completely. Original and copy are fully independent. Change anything in one — the other doesn't care.
Most common approach for deep copy in real projects — copy constructor, or serialize then deserialize, or libraries like ModelMapper.
#Java #CoreJava #DeepCopy #ShallowCopy
Serialization in Java
Serialization converts an object into a byte stream so it can be saved to a file, sent over a network, or stored in cache.
Deserialization is the reverse — byte stream back to object.
Serializable is a marker interface — no methods, just tells JVM this class can be serialized.
Used for — saving object state to file, sending objects between services, storing in Redis, deep copying objects.
The output is binary — not human readable. If you need human readable use JSON instead.
#Java #Serialization #CoreJava
transient vs volatile
Two completely different problems — just both are field modifiers.
volatile — always read fresh value from main memory, bypassing CPU cache. Solves visibility problem between threads.
transient — skip this field during serialization. Field won't be written to file or sent over network. Most common use — sensitive data like passwords and tokens you never want leaving the application.
#Java #CoreJava #Volatile #Transient #Threads
Reflection in Java
Reflection API gives access to private fields, methods, constructors and annotations at runtime — bypassing normal access rules.
Spring uses it heavily — creating beans without you calling new, injecting dependencies into private fields with @Autowired, scanning annotations like @Service and @Transactional.
JUnit finds @Test methods via reflection. Jackson reads object fields to convert to JSON. Hibernate maps fields to database columns.
Downside — slow, breaks encapsulation, and Java 9+ restricts access to internal JDK classes via module system. One of the biggest reasons companies stayed on Java 8 for so long.
#Java #Reflection #CoreJava #Spring
Abstract Class vs Interface
Abstract class — use when classes share common state and behavior. Supports only one extends. Can have instance fields, concrete methods, abstract methods.
Interface — use when unrelated classes share a contract. A class can implement many interfaces. Since Java 8 supports default and static methods too.
Real use case difference — abstract class is what you ARE, interface is what you CAN DO.
Vehicle is an abstract class — Car and Truck share speed, acceleration, fuel logic.
Flyable is an interface — Bird, Airplane, Superman are completely unrelated but all can fly.
#Java #CoreJava #AbstractClass #Interface #OOP
Design Patterns in Java
Patterns are proven solutions to common software design problems. Three categories:
Creational — how objects are created.
Singleton — one instance across entire app. DB connections, Logger, Spring beans by default.
Factory — delegate object creation to a method. Spring BeanFactory, JDBC DriverManager.
Builder — construct complex objects step by step. Lombok @Builder, HTTP request builders.
Structural — how objects are composed.
Proxy, Adapter, Decorator — Spring AOP uses Proxy pattern heavily.
Behavioral — how objects communicate.
Observer, Strategy, Template Method — used everywhere in frameworks.
#Java #DesignPatterns #CoreJava #Spring
== compares memory addresses — are these two variables pointing to the same object in heap?
equals() compares content — are these two objects meaningfully the same?
Default equals() from Object class just does ==. The magic happens when you override it — like String does, comparing character by character.
Two Dogs with the same name are two different objects at different heap addresses. == returns false. Override equals() and it returns true.
Important rule — whenever you override equals() always override hashCode() too. Otherwise HashMap and HashSet break completely.
#Java #CoreJava #Equals #Hashcode
Shallow Copy vs Deep Copy
Shallow copy — copies the object but nested objects are still shared. Change a nested object in the copy and the original changes too.
Deep copy — copies everything completely. Original and copy are fully independent. Change anything in one — the other doesn't care.
Most common approach for deep copy in real projects — copy constructor, or serialize then deserialize, or libraries like ModelMapper.
#Java #CoreJava #DeepCopy #ShallowCopy
Serialization in Java
Serialization converts an object into a byte stream so it can be saved to a file, sent over a network, or stored in cache.
Deserialization is the reverse — byte stream back to object.
Serializable is a marker interface — no methods, just tells JVM this class can be serialized.
Used for — saving object state to file, sending objects between services, storing in Redis, deep copying objects.
The output is binary — not human readable. If you need human readable use JSON instead.
#Java #Serialization #CoreJava
transient vs volatile
Two completely different problems — just both are field modifiers.
volatile — always read fresh value from main memory, bypassing CPU cache. Solves visibility problem between threads.
transient — skip this field during serialization. Field won't be written to file or sent over network. Most common use — sensitive data like passwords and tokens you never want leaving the application.
#Java #CoreJava #Volatile #Transient #Threads
Reflection in Java
Reflection API gives access to private fields, methods, constructors and annotations at runtime — bypassing normal access rules.
Spring uses it heavily — creating beans without you calling new, injecting dependencies into private fields with @Autowired, scanning annotations like @Service and @Transactional.
JUnit finds @Test methods via reflection. Jackson reads object fields to convert to JSON. Hibernate maps fields to database columns.
Downside — slow, breaks encapsulation, and Java 9+ restricts access to internal JDK classes via module system. One of the biggest reasons companies stayed on Java 8 for so long.
#Java #Reflection #CoreJava #Spring
Abstract Class vs Interface
Abstract class — use when classes share common state and behavior. Supports only one extends. Can have instance fields, concrete methods, abstract methods.
Interface — use when unrelated classes share a contract. A class can implement many interfaces. Since Java 8 supports default and static methods too.
Real use case difference — abstract class is what you ARE, interface is what you CAN DO.
Vehicle is an abstract class — Car and Truck share speed, acceleration, fuel logic.
Flyable is an interface — Bird, Airplane, Superman are completely unrelated but all can fly.
#Java #CoreJava #AbstractClass #Interface #OOP
Design Patterns in Java
Patterns are proven solutions to common software design problems. Three categories:
Creational — how objects are created.
Singleton — one instance across entire app. DB connections, Logger, Spring beans by default.
Factory — delegate object creation to a method. Spring BeanFactory, JDBC DriverManager.
Builder — construct complex objects step by step. Lombok @Builder, HTTP request builders.
Structural — how objects are composed.
Proxy, Adapter, Decorator — Spring AOP uses Proxy pattern heavily.
Behavioral — how objects communicate.
Observer, Strategy, Template Method — used everywhere in frameworks.
#Java #DesignPatterns #CoreJava #Spring
🔒 JPA — @Transactional
"The session stays open until the job finishes."
• Guarantees ACID — all or nothing
• Keeps Hibernate session alive for the entire method
• Without it → session closes after first query → LazyInitializationException
• readOnly=true → skips dirty checking → faster reads, no accidental writes
• spring.jpa.open-in-view=true (default) keeps session open till HTTP response — hides real problems, disable it
• Dirty checking: Hibernate tracks changes and auto-flushes at transaction end
💡 Reminder: No @Transactional = no session = no lazy loading.
#Java #JPA #Hibernate #Transactional #ACID #SpringBoot #EPAM
"The session stays open until the job finishes."
• Guarantees ACID — all or nothing
• Keeps Hibernate session alive for the entire method
• Without it → session closes after first query → LazyInitializationException
• readOnly=true → skips dirty checking → faster reads, no accidental writes
• spring.jpa.open-in-view=true (default) keeps session open till HTTP response — hides real problems, disable it
• Dirty checking: Hibernate tracks changes and auto-flushes at transaction end
💡 Reminder: No @Transactional = no session = no lazy loading.
#Java #JPA #Hibernate #Transactional #ACID #SpringBoot #EPAM
🔧 JPA — FETCH JOIN & @EntityGraph
"Tell Hibernate exactly what to load, exactly when you need it."
• FETCH JOIN → collapses N+1 into 1 single SQL query
• @EntityGraph → same idea, but without writing JPQL
• Both keep FetchType LAZY but load eagerly on demand
• Loop after FETCH JOIN = iterating memory, not hitting DB
• Use FETCH JOIN when you KNOW you'll need the children
• Don't use it blindly — fetching unnecessary data is still waste
💡 Reminder: LAZY is the default. FETCH JOIN is your controlled override.
#Java #JPA #Hibernate #FetchJoin #EntityGraph #SpringBoot #EPAM
"Tell Hibernate exactly what to load, exactly when you need it."
• FETCH JOIN → collapses N+1 into 1 single SQL query
• @EntityGraph → same idea, but without writing JPQL
• Both keep FetchType LAZY but load eagerly on demand
• Loop after FETCH JOIN = iterating memory, not hitting DB
• Use FETCH JOIN when you KNOW you'll need the children
• Don't use it blindly — fetching unnecessary data is still waste
💡 Reminder: LAZY is the default. FETCH JOIN is your controlled override.
#Java #JPA #Hibernate #FetchJoin #EntityGraph #SpringBoot #EPAM
🚨 JPA — The N+1 Problem
"You asked for 1 list. Hibernate made 1001 queries."
• 1 query fetches all parents
• N queries fire — one per parent — to fetch their children
• With 1000 users → 1001 DB hits
• Root cause: LAZY loading triggered inside a loop
• Grows silently — works fine in dev, crashes in production
• How to spot it: same query shape repeating in logs with different IDs
• Enable spring.jpa.show-sql=true to see it happening live
💡 Reminder: The loop is not the problem. DB roundtrips inside the loop are.
#Java #JPA #Hibernate #NPlus1 #Performance #SpringBoot #EPAM
"You asked for 1 list. Hibernate made 1001 queries."
• 1 query fetches all parents
• N queries fire — one per parent — to fetch their children
• With 1000 users → 1001 DB hits
• Root cause: LAZY loading triggered inside a loop
• Grows silently — works fine in dev, crashes in production
• How to spot it: same query shape repeating in logs with different IDs
• Enable spring.jpa.show-sql=true to see it happening live
💡 Reminder: The loop is not the problem. DB roundtrips inside the loop are.
#Java #JPA #Hibernate #NPlus1 #Performance #SpringBoot #EPAM
⚡ JPA — FetchType: LAZY vs EAGER
"EAGER loads children when parent is fetched. LAZY loads children only when you actually call them."
• LAZY = load on demand ✅
• EAGER = load everything immediately ⚠️
• Default: @OneToMany → LAZY, @ManyToOne → EAGER, @OneToOne → EAGER
• EAGER with large data = fetching millions of rows you didn't ask for
• Always prefer LAZY, load eagerly only when you explicitly need it
• Use FETCH JOIN or @EntityGraph to control loading, not EAGER
💡 Golden rule: Always LAZY. Load eagerly only when you choose to.
#Java #JPA #Hibernate #SpringBoot #Backend #EPAM
"EAGER loads children when parent is fetched. LAZY loads children only when you actually call them."
• LAZY = load on demand ✅
• EAGER = load everything immediately ⚠️
• Default: @OneToMany → LAZY, @ManyToOne → EAGER, @OneToOne → EAGER
• EAGER with large data = fetching millions of rows you didn't ask for
• Always prefer LAZY, load eagerly only when you explicitly need it
• Use FETCH JOIN or @EntityGraph to control loading, not EAGER
💡 Golden rule: Always LAZY. Load eagerly only when you choose to.
#Java #JPA #Hibernate #SpringBoot #Backend #EPAM
🔗 JPA — Cascade Types
"When something happens to the parent, the same happens to the child."
• PERSIST → save parent = save children
• REMOVE → delete parent = delete children
• MERGE → update parent = update children
• ALL → all of the above
• Cascade is NOT a DB feature — it's pure Hibernate logic
• DB has its own version: ON DELETE CASCADE (they're independent)
• Without cascade → you must save/delete every child manually
💡 Reminder: Cascade flows Parent → Child, not the other way around.
#Java #JPA #Hibernate #SpringBoot #Backend #EPAM
"When something happens to the parent, the same happens to the child."
• PERSIST → save parent = save children
• REMOVE → delete parent = delete children
• MERGE → update parent = update children
• ALL → all of the above
• Cascade is NOT a DB feature — it's pure Hibernate logic
• DB has its own version: ON DELETE CASCADE (they're independent)
• Without cascade → you must save/delete every child manually
💡 Reminder: Cascade flows Parent → Child, not the other way around.
#Java #JPA #Hibernate #SpringBoot #Backend #EPAM