While debugging a Hibernate issue recently, I came across something interesting 👇 `org.hibernate.ObjectNotFoundException` — a small error with a big lesson. At first glance, it looked like a typical lazy loading problem. But the actual root cause was deeper. 🔍 What was happening? Hibernate created a proxy for a related entity, but when it tried to initialize it, the corresponding row didn’t exist in the database. 👉 In short: The application assumed data integrity, but the database told a different story. ⚠️ The tricky part? The exception wasn’t thrown during query execution. It appeared during debugging when `toString()` was triggered on a proxy object. 💡 Key learnings from this: 🔹 ORM frameworks don’t guarantee data consistency — your database does 🔹 Lazy loading can hide issues until runtime (or even debug time) 🔹 Using Lombok `@ToString` blindly on entities can backfire 🔹 Circular relationships (OneToMany ↔ ManyToOne) can lead to unexpected behavior 🛠 What helped fix it: ✔ Verifying referential integrity at the database level ✔ Avoiding unnecessary eager access during debugging ✔ Restricting `toString()` to only essential fields ✔ Using LEFT JOIN fetch where relationships may be optional 🚀 Takeaway: Most production issues are not about complex logic — they are about mismatches between your assumptions and actual data. Always trust your database more than your ORM. #Java #Hibernate #SpringBoot #BackendDevelopment #Debugging #SoftwareEngineering #Production #ProductionIssues #ErrorHandling
Debugging Hibernate ObjectNotFoundException: Database Integrity vs ORM Assumptions
More Relevant Posts
-
HIBERNATE'S HIDDEN TRAP: EAGER VS LAZY LOADING (PART 1) 🛌⚡ In Hibernate, there are two ways to load data, and both of them can kill your performance if you aren't careful. 1. THE EAGER TRAP 🍔 Eager loading is "greedy." It fetches the parent and all related children in one go. Sounds efficient? Until you realize that fetching one User just triggered a massive chain reaction that loaded 500 Orders, 2000 Items, and 5000 Reviews into memory. Your "simple" query just became a memory bomb. 2. THE LAZY TRAP 💤 Lazy loading is "procrastinating." it only fetches the children when you actually ask for them. But if you ask for them inside a loop, you trigger the N+1 problem. One query to fetch the list, and then 100 more queries to fetch the details. 3. THE "DETACHED ENTITY" CRASH 💥 We’ve all seen the LazyInitializationException. This happens when you try to access lazy data after the DB transaction has closed. It’s Hibernate’s way of saying, "You should have asked for this earlier!" In Part 2, I’ll show you how to use Join Fetching to get the best of both worlds. #Hibernate #Java #ORM #DatabasePerformance #BackendDevelopment #SoftwareEngineering #JavaPersistenceAPI #DatabaseDesign #PerformanceTuning #TechTips #CodingLife #SoftwareArchitecture #API #SQL
To view or add a comment, sign in
-
-
🚀 Day21 – Hibernate One-to-One Mapping Today I explored One-to-One relationship in Hibernate, a fundamental concept for linking two entities directly. 🔹 What I Worked On: ✔️ Implemented One-to-One mapping using annotations ✔️ Used @OneToOne and @JoinColumn 🔗 ✔️ Connected two entities with a single relationship ✔️ Stored linked data across tables 🔹 Concept Understanding: 👉 One record in a table is linked to exactly one record in another 👉 Example: One Student → One ID Card 🔹 Workflow: ➡️ Created two entity classes ➡️ Applied @OneToOne mapping ➡️ Configured Hibernate ➡️ Saved linked objects ➡️ Verified relationship in database ✅ 🔹 Key Learnings: ✨ Clear understanding of One-to-One relationships ✨ Learned how foreign keys work in mapping ✨ Understood uni-directional vs bi-directional mapping ✨ Improved ORM design concepts 🔹 Challenges Faced: ⚡ Deciding owning side of relationship ⚡ Correct usage of @JoinColumn ⚡ Handling cascading operations 🔹 What’s Next: 🚀 Explore One-to-Many mapping 🚀 Perform CRUD with relationships 🚀 Dive deeper into fetch types #Java #Hibernate #ORM #BackendDevelopment #LearningJourney Guided by, Anand Kumar Buddarapu sir, Saketh Kallepu sir, Uppugundla Sairam sir.
To view or add a comment, sign in
-
I recently made a seemingly small architectural change in one of my projects using Hibernate ORM and the performance improvement was not just noticeable, it was unexpected. Most developers assume “clean” relational design is always the right choice but my project proves that assumption turned out to be wrong. I replaced a classic table relationship (2 tables with back-reference, or even 3 with a join table) with a simple JSON field. Result: a surprisingly big performance boost. Why? No joins. Less complexity and Faster reads. If you’re using Hibernate, I strongly recommend checking out the JSON support from Vlad Mihalcea. It makes integration straightforward. But here’s the catch: JSON breaks easily when your model changes. You lose schema safety and old data can become unreadable. To solve this, I built a small helper tool to handle versioning and keep things stable. Here is it: https://lnkd.in/eujvVewK JSON can be a serious performance win but only if you handle evolution properly. Otherwise, you’re trading one problem for another. #Java #Hibernate #JPA #Performance #SoftwareArchitecture #Backend #DatabaseDesign #JSON
To view or add a comment, sign in
-
-
🚀 Avoiding the N+1 Problem in Spring Boot (Hibernate) The N+1 problem is a common performance issue where: 👉 1 query fetches parent data 👉 N additional queries fetch related child data 💡 Why does this happen? Because of Lazy Loading (FetchType.LAZY) — Hibernate loads related data only when accessed 📌 Mapping Behavior Matters 🔹 @OneToMany - Default: LAZY 🚨 (Most common cause of N+1) - Accessing children inside a loop triggers multiple queries 🔹 @ManyToOne - Default: EAGER - Usually avoids N+1 - ⚠️ Can lead to unnecessary data fetching 🔹 @OneToOne - Default: EAGER - Safe by default - ⚠️ If changed to LAZY → can cause N+1 📍 Example Scenario - Entity1 → has relation with Entity2 - Fetch list of Entity1 - Access Entity2 inside a loop ⚠️ Hibernate executes: 1 query for Entity1 + N queries for Entity2 → N+1 problem ❌ ✅ Solution: Use JOIN FETCH Example: SELECT e1 FROM Entity1 e1 JOIN FETCH e1.entity2 ✔ Loads both entities in a single query ✔ Eliminates multiple database calls ✔ Improves performance significantly ⚠️ Be careful with @OneToMany - Can produce duplicate parent records due to JOINs - May load large datasets into memory - Use DISTINCT to avoid duplicates - Prefer pagination for large data 🎯 Best Practice 👉 Prefer LAZY loading for flexibility 👉 Use JOIN FETCH when related data is required 👉 Avoid blindly relying on EAGER loading 🔥 Key Takeaway Understanding fetch strategies + entity mappings = Better performance 🚀 #SpringBoot #Hibernate #JPA #Java #Performance #Backend #Optimization #joinfetch
To view or add a comment, sign in
-
Setting every JPA relationship to FetchType.LAZY is the easy part. Living with the consequences is where most projects quietly fall apart. Here is what happens. You mark all your @ManyToOne and @OneToOne relationships as LAZY because every blog post tells you to. Your entities look clean. Then you write a service method that loads a Transaction and accesses transaction.getWorkspace().getName(). If the persistence context is still open, Hibernate silently fires a second query. If it is closed - which it will be once you disable OSIV like you should - you get a LazyInitializationException. The knee-jerk fix is to flip back to EAGER. Now every query that touches Transaction loads the Workspace too, whether the caller needs it or not. You just traded one problem for a worse one that is harder to detect. The actual solution is @EntityGraph on the repository method that needs the association: @EntityGraph(attributePaths = {"workspace", "createdByUser"}) List findByWorkspaceIdAndDateBetween(...) This tells Hibernate: for this specific query, load workspace and createdByUser in a single JOIN. Every other method on the same repository keeps lazy loading. You get per-method fetch control without touching the entity definition. The pattern I follow: entities are always LAZY. The repository method decides what to load based on the use case it serves. If a method does not access a relationship, it pays zero cost for it. If it does, the @EntityGraph makes it explicit and testable. To verify it works, I clear the persistence context in tests (entityManager.clear()), then access the relationship on the detached entity. If @EntityGraph did its job, no exception. If it did not, LazyInitializationException tells me exactly what I missed. Lazy-by-default is not a strategy. Lazy-by-default with explicit entity graphs per use case is. #SpringBoot #JPA #Hibernate #BackendDevelopment
To view or add a comment, sign in
-
Lazy vs Eager Loading — The N+1 Problem Every Java Dev Must Know One of the most common performance killers in Spring Data JPA is the infamous N+1 query problem — and it all starts with how you configure your fetch strategy. By default, @OneToMany and @ManyToMany use LAZY loading — related data is fetched only when accessed. Meanwhile, @ManyToOne and @OneToOne default to EAGER — data is loaded immediately with the parent. The trap? When you load a list of 100 customers and then access their orders in a loop: List<Customer> customers = customerRepo.findAll(); // 1 query for (Customer c : customers) { c.getOrders().size(); // 100 more queries! } // Total: 101 SQL queries = performance disaster Solutions that actually work: // 1. JOIN FETCH in JPQL @Query("SELECT c FROM Customer c JOIN FETCH c.orders") List<Customer> findAllWithOrders(); // 2. @EntityGraph @EntityGraph(attributePaths = {"orders"}) List<Customer> findAll(); Rule of thumb: ✅ Keep FetchType.LAZY as default ✅ Use JOIN FETCH or @EntityGraph when you know you need related data ✅ Enable Hibernate SQL logging to detect N+1 early ❌ Never switch everything to EAGER — that's trading N+1 for over-fetching #Java #SpringBoot #BackendDevelopment #SpringDataJPA #Performance #LearningInPublic
To view or add a comment, sign in
-
-
🚀 Mastering Persistence in Spring Data JPA: persist() vs. merge() vs. save() Ever wondered which method to use when saving data in Java? Choosing the wrong one can lead to unnecessary SQL queries or even dreaded EntityExistsException errors. Here is the breakdown of the "Big Three": 🔹 1. persist() – The "New Only" Approach What it does: Takes a brand-new (transient) entity and makes it managed. It schedules an INSERT. Best for: Creating new records when you are sure they don't exist yet. Watch out: It will throw an exception if the entity is already detached or has an ID that exists in the DB. 🔹 2. merge() – The "Reconnector" What it does: Takes a detached entity (one that was loaded in a different session) and copies its state onto a new managed version. Best for: Updating existing records that were passed through different layers of your app (e.g., from a REST controller). Watch out: It creates a copy. You must use the returned object for further changes! 🔹 3. save() – The Spring Data Way What it does: A smart wrapper provided by Spring Data JPA. It checks if the entity is "new." If yes, it calls persist(); if not, it calls merge(). Best for: Most standard repository patterns. It’s the "safe bet" for 90% of use cases. Watch out: Because it checks state first, it might trigger an extra SELECT query to decide whether to insert or update. 💡 Pro Tip: If you are building high-performance systems with massive inserts, using persist() directly via the EntityManager can sometimes be more efficient than the generic save() method. Check out the infographic below for a quick visual cheat sheet! 📊 #Java #SpringBoot #JPA #Hibernate #SoftwareEngineering #BackendDevelopment
To view or add a comment, sign in
-
-
🔥 𝗪𝗵𝗮𝘁 𝗮 𝗱𝗲𝗯𝘂𝗴𝗴𝗶𝗻𝗴 𝗷𝗼𝘂𝗿𝗻𝗲𝘆 𝘄𝗶𝘁𝗵 𝗛𝗶𝗯𝗲𝗿𝗻𝗮𝘁𝗲 𝘁𝗼𝗱𝗮𝘆 — 𝗮𝗻𝗱 𝗜 𝗹𝗲𝗮𝗿𝗻𝗲𝗱 𝗺𝗼𝗿𝗲 𝗶𝗻 𝟮 𝗵𝗼𝘂𝗿𝘀 𝘁𝗵𝗮𝗻 𝗜 𝘄𝗼𝘂𝗹𝗱 𝗶𝗻 𝟮 𝘄𝗲𝗲𝗸𝘀 𝗼𝗳 𝗷𝘂𝘀𝘁 𝗿𝗲𝗮𝗱𝗶𝗻𝗴. Here's the full story: ❌ 𝗣𝗿𝗼𝗯𝗹𝗲𝗺: LazyInitializationException "Cannot lazily initialize collection of role Company.jobs — no session" My @OneToMany(fetch = LAZY) jobs list in Company was throwing this every time I hit the API. 🔁 𝗔𝘁𝘁𝗲𝗺𝗽𝘁 𝟭 — @𝗧𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻𝗮𝗹 Added it to the service method. Fixed the exception... but then I noticed something in the logs. Hibernate was firing N+1 queries: → 1 query for all companies → 1 query per company to fetch its jobs → 5 companies = 6 queries. Not good. 🔁 𝗔𝘁𝘁𝗲𝗺𝗽𝘁 𝟮 — 𝗙𝗲𝘁𝗰𝗵𝗧𝘆𝗽𝗲.𝗘𝗔𝗚𝗘𝗥 Worked, but it always loads jobs — even when I don't need them. A performance trap waiting to happen. ✅ 𝗙𝗶𝗻𝗮𝗹 𝗳𝗶𝘅 — 𝗝𝗢𝗜𝗡 𝗙𝗘𝗧𝗖𝗛 @Query("SELECT c FROM Company c LEFT JOIN FETCH c.jobs") → 1 single SQL query → No session dependency → No N+1 problem → Maximum performance 🚀 💡 𝗕𝗼𝗻𝘂𝘀 𝗹𝗲𝘀𝘀𝗼𝗻: Don't use @Lob on a String field in PostgreSQL with Hibernate 6. PostgreSQL LOBs use numeric OIDs internally — so Hibernate tries to read your text as a long and crashes with "bad value for type long". Removing @Lob fixed it instantly. 𝗧𝗵𝗲 𝗹𝗲𝗮𝗿𝗻𝗶𝗻𝗴 𝗷𝗼𝘂𝗿𝗻𝗲𝘆: LazyInitializationException → @Transactional (N+1 problem) → EAGER (always loads, bad practice) → JOIN FETCH ✅ (one query, perfect) Sometimes the best way to understand a tool deeply is to break it in every possible way first. 😄 #Java #SpringBoot #Hibernate #JPA #Backend #SpringAI #SpringUsers #JavaDevelopmentDesign
To view or add a comment, sign in
-
Spring Boot's OSIV default turns your JSON serializer into a hidden query engine I'm building a personal finance platform with Spring Boot 3.5 + Java 21. The first thing I disabled was Open Session in View. Spring Boot ships with spring.jpa.open-in-view=true. That means Hibernate keeps a database connection open through the entire HTTP request - including JSON serialization. When Jackson walks your entity graph to build a response, every uninitialized lazy relationship triggers a database query. Your serializer is now executing SQL. In a load test with HikariCP's default pool of 10 connections and around 150 concurrent requests, this is where things break. Each request holds a connection for the full request lifecycle instead of just the service layer. The pool exhausts, threads queue up, and response times spike. The tricky part is that it works fine in dev when you're the only user. Disabling OSIV forces you to think about what data you actually need. You fetch it explicitly in the service layer with JOIN FETCH or projections, map it to a DTO, and the connection goes back to the pool before serialization even starts. It's more code upfront but the data flow becomes visible instead of hidden behind proxy magic. The second thing I changed was ddl-auto. Hibernate's update mode can generate schema changes automatically, but it can't rename columns, drop unused indexes, or migrate data. It produces a schema that looks right but drifts from what you intended. I use validate with Flyway migrations instead - every schema change is an explicit, versioned SQL file. If the code and the database disagree, the app refuses to start rather than silently diverging. These two defaults share the same problem. They hide complexity that surfaces as production issues. OSIV hides query execution. ddl-auto update hides schema drift. In both cases, making the behavior explicit costs more effort early but removes an entire class of debugging later. #SpringBoot #Java #BuildInPublic #BackendDevelopment
To view or add a comment, sign in
-
Yesterday we talked about how Lombok can crash your app through Hibernate relationships. Today, let’s talk about the other silent killer in those exact same entities: The N+1 Query Problem. If you work with Spring Data JPA long enough, you will eventually write a piece of code that looks completely fine, passes all unit tests, and then completely chokes your database in production. Usually, the culprit is the N+1 problem. The Trap: Let’s say you have a User entity with a @OneToMany relationship to Order. You want to fetch 100 users and print their order totals. You write a simple repository call: userRepository.findAll() (This is 1 query).Then, you loop through those 100 users and call user.getOrders(). What you think happens: Hibernate fetches the users and their orders efficiently. What actually happens: Because relationships are (and should be!) FetchType.LAZY by default, Hibernate executes 1 query to get the 100 users, and then 100 additional queries—one for each user—to fetch their orders. You just hit your database 101 times for a single API request. Multiply that by 1,000 concurrent users, and your DBA is calling you in a panic. 😅 The Senior Fixes: 1. The Quick Fix: JOIN FETCH Instead of using standard findAll(), write a custom JPQL query: SELECT u FROM User u JOIN FETCH u.orders This forces Hibernate to grab everything in a single, efficient JOIN query. 2. The Elegant Fix: @EntityGraph If you don't want to write custom queries, Spring Boot lets you use Entity Graphs to dynamically define which lazy associations should be fetched eagerly for a specific method call. 3. The Ultimate Fix: DTO Projections Stop fetching full Managed Entities if you just need to read data! Write a query that maps directly to a Record or DTO. It bypasses the Hibernate proxy lifecycle entirely and is blazing fast. JPA makes the easy things trivial, but it makes the hard things incredibly dangerous if you don't look at the generated SQL. What is your team's standard way of catching N+1 queries before they hit production? Do you use a specific tool, or rely on code reviews? 👇 #Java #SpringBoot #Hibernate #BackendDevelopment #Microservices #SoftwareEngineering #PerformanceTuning #CleanCode
To view or add a comment, sign in
Explore related topics
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development