Recently, while working with Spring Boot and Hibernate, I came across a very common performance issue called the N+1 query problem. At first, everything looked fine. I was fetching all orders using: List<Order> orders = orderRepository.findAll(); This runs just one query on the orders table. But later, when I tried to access the customer information inside a loop: for (Order order : orders) { System.out.println(order.getCustomer().getName()); } Hibernate started firing one extra query for each order because of lazy loading. So if there are 100 orders, instead of 1 query, it becomes 101 queries. That’s when I understood how easily performance can be affected if we don’t pay attention to fetch strategies. To solve this, I explored a few approaches: 1. JOIN FETCH (Most Common) Fetch parent and child entities in a single query: @Query("SELECT o FROM Order o JOIN FETCH o.customer") List<Order> findAllOrdersWithCustomer(); This generates: SELECT o.*, c.* FROM orders o JOIN customer c ON o.customer_id = c.id; Now only 1 query runs instead of 101. 2. @EntityGraph A cleaner Spring Data JPA solution: @EntityGraph(attributePaths = {"customer"}) List<Order> findAll(); This tells Hibernate to fetch customer along with orders. Very clean and avoids custom JPQL. 3. Batch Fetching (@BatchSize) Very useful for @OneToMany relationships. @OneToMany(mappedBy = "customer") @BatchSize(size = 20) private List<Order> orders; Instead of firing one query per customer, Hibernate fetches in batches: SELECT * FROM orders WHERE customer_id IN (1,2,3,...20) This significantly reduces query count. 4. DTO Projection Best for API responses when only selected fields are needed. @Query(""" SELECT new com.example.dto.OrderDto( o.id, c.name ) FROM Order o JOIN o.customer c """) List<OrderDto> findAllOrderDtos(); This is fast, efficient, and avoids unnecessary entity loading. Learning things like this makes backend development really interesting for me — sometimes the code works perfectly, but under the hood it may still be inefficient. #SpringBoot #Hibernate #Java #BackendDevelopment #SoftwareEngineering #LearningJourney
Solving N+1 Query Problem in Spring Boot with Hibernate
More Relevant Posts
-
🚨 Performance Issues with Hibernate (and how to avoid them) Hibernate is powerful—but if you’re not careful, it can quietly destroy your application's performance. After working on large-scale systems, these are the most common issues I keep seeing: 🔴 1. N+1 Query Problem You fetch a list… and Hibernate fires one query per item. 👉 Example: Loading 100 orders = 101 queries 💥 Impact: Massive latency + database overload ✅ Fix: ▫️ Use JOIN FETCH ▫️ Use @EntityGraph ▫️ Consider DTO projections 🔴 2. LazyInitializationException (and bad fixes) Developers often switch everything to EAGER to "fix" it. 💥 Impact: Over-fetching → memory waste + slow queries ✅ Fix: ▫️ Keep LAZY by default ▫️ Control fetching explicitly in queries 🔴 3. Too Many SELECTs (chatty persistence layer) Multiple small queries instead of one optimized query. 💥 Impact: Network overhead + DB stress ✅ Fix: ▫️ Batch fetching (hibernate.default_batch_fetch_size) ▫️ Use IN queries ▫️ Optimize relationships 🔴 4. Missing Indexes Hibernate won’t save you from bad database design. 💥 Impact: Full table scans on large datasets ✅ Fix: ▫️ Add indexes on foreign keys and filters ▫️ Analyze execution plans 🔴 5. Dirty Checking Overhead Hibernate tracks all managed entities. 💥 Impact: High memory + CPU usage in large transactions ✅ Fix: ▫️ Use @Transactional(readOnly = true) when possible ▫️ Clear persistence context (EntityManager.clear()) 🔴 6. Uncontrolled Flushes Hibernate flushes more often than you expect. 💥 Impact: Extra queries + slower transactions ✅ Fix: ▫️ Use FlushModeType.COMMIT ▫️ Control flush manually in batch operations 🔴 7. Fetching Entire Entities When You Only Need a Few Fields Loading full objects when only 2–3 fields are needed. 💥 Impact: Memory waste + unnecessary joins ✅ Fix: ▫️ Use DTO projections (SELECT new ...) ▫️ Native queries when needed 💡 Final Thought Hibernate doesn’t make your app slow 👉 misusing Hibernate does. If you're building high-performance systems, you must understand what’s happening behind the scenes. 💬 Have you ever debugged a Hibernate performance issue in production? What was the root cause? #Java #Hibernate #Performance #Backend #SpringBoot #CleanCode
To view or add a comment, sign in
-
-
𝐋𝐚𝐳𝐲𝐈𝐧𝐢𝐭𝐢𝐚𝐥𝐢𝐳𝐚𝐭𝐢𝐨𝐧𝐄𝐱𝐜𝐞𝐩𝐭𝐢𝐨𝐧 𝐢𝐧 𝐏𝐫𝐨𝐝𝐮𝐜𝐭𝐢𝐨𝐧: 𝐀 𝐃𝐞𝐬𝐢𝐠𝐧 𝐏𝐫𝐨𝐛𝐥𝐞𝐦, 𝐍𝐨𝐭 𝐉𝐮𝐬𝐭 𝐚 𝐁𝐮𝐠 If you have worked with Spring Boot and Hibernate/JPA, you know this pain well: -Your code runs perfectly in local tests and Postman. -It explodes in production with this error: “could not initialize proxy, no Session” This exception is sneaky. It rarely shows up during development, everything looks fine locally. But the moment you hit production or QA under real load, it suddenly appears, often during JSON serialization. 𝐖𝐡𝐚𝐭’𝐬 𝐀𝐜𝐭𝐮𝐚𝐥𝐥𝐲 𝐇𝐚𝐩𝐩𝐞𝐧𝐢𝐧𝐠? -Imagine a Customer entity with basic info (id, name, email) and a list of Documents (files or contracts) linked via @OneToMany (lazy by default). 𝐂𝐮𝐬𝐭𝐨𝐦𝐞𝐫 𝐜𝐮𝐬𝐭𝐨𝐦𝐞𝐫 = 𝐜𝐮𝐬𝐭𝐨𝐦𝐞𝐫𝐑𝐞𝐩𝐨𝐬𝐢𝐭𝐨𝐫𝐲.𝐟𝐢𝐧𝐝𝐁𝐲𝐈𝐝(𝐢𝐝).𝐨𝐫𝐄𝐥𝐬𝐞𝐓𝐡𝐫𝐨𝐰(); Here, customer.getDocuments() is not real data but it’s a Hibernate proxy, a lazy placeholder. It promises to load the documents later… but only if the Hibernate Session is still open. **𝐖𝐡𝐞𝐫𝐞 𝐈𝐭 𝐁𝐫𝐞𝐚𝐤𝐬 -The repository method ends → the Session closes immediately. Later, in the controller or outside the method (while building JSON), the code accesses customer.getDocuments(). Hibernate tries to fetch the data but the Session is gone. 𝐑𝐞𝐬𝐮𝐥𝐭: 𝐋𝐚𝐳𝐲𝐈𝐧𝐢𝐭𝐢𝐚𝐥𝐢𝐳𝐚𝐭𝐢𝐨𝐧𝐄𝐱𝐜𝐞𝐩𝐭𝐢𝐨𝐧 !!𝐀 𝐐𝐮𝐢𝐜𝐤 𝐅𝐢𝐱 (Avoid This) @OneToMany(fetch = FetchType.EAGER) It stops the exception temporarily, but creates bigger problems: -N+1 queries -Unnecessary data loading -Higher memory usage -Slower performance at scale -we are just hiding an architecture smell. **𝐓𝐡𝐞 𝐏𝐫𝐨𝐟𝐞𝐬𝐬𝐢𝐨𝐧𝐚𝐥 𝐖𝐚𝐲 𝐭𝐨 𝐇𝐚𝐧𝐝𝐥𝐞 𝐈𝐭** 1. Keep Transactions at the Service Layer @Transactional(readOnly = true) public CustomerDTO getCustomerWithDocuments(Long id) { Customer customer = repository.findByIdWithDocuments(id); return mapper.toDTO(customer); // Safe lazy loading inside transaction } 2. Use JOIN FETCH Intentionally @Query("SELECT c FROM Customer c JOIN FETCH c.documents WHERE c.id = :id") Customer findByIdWithDocuments(@Param("id") Long id); 3. Never Return Entities from Controllers Map to DTOs (or records) inside the transaction. This prevents lazy loading issues, gives full control over the response, improves security, and cleans up your architecture. *𝐁𝐨𝐧𝐮𝐬 𝐓𝐢𝐩: Set >𝐬𝐩𝐫𝐢𝐧𝐠.𝐣𝐩𝐚.𝐨𝐩𝐞𝐧-𝐢𝐧-𝐯𝐢𝐞𝐰=𝐟𝐚𝐥𝐬𝐞 in production. It forces better design and eliminates hidden LazyInitializationExceptions. #Java #SpringBoot #Hibernate #JPA #BackendDevelopment #CleanArchitecture #SystemDesign #LazyInitializationExceptions
To view or add a comment, sign in
-
Request life cycle (focused on Transactional, Hibernate, JPA & HikariCP) 1. Client sends HTTP request (POST /api/v1/orders) 2. OS receives TCP bytes → places in socket buffer 3. Tomcat picks up bytes → parses HTTP headers & body 4. Tomcat assigns request to a thread 5. Jackson deserialises JSON → Java object 6. Request routed to matching Controller via @RequestMapping 7. Controller validates input → calls Service 8. @Transactional proxy intercepts → opens DB connection → BEGIN 9. Service applies business logic → calls Repository 10. Spring Data JPA reads method name → generates JPQL 11. JPQL handed to EntityManager → Hibernate translates to SQL 12. Hibernate checks L1 cache → cache miss → sends SQL to MySQL 13. MySQL parses SQL → optimiser picks execution plan 14. InnoDB reads rows from disk/buffer → sends result back 15. Hibernate maps columns → @Entity Java object → stored in L1 cache 16. Service persists new data → Hibernate generates INSERT/UPDATE 17. MySQL executes write → acquires row locks → acknowledges 18. Method returns → @Transactional proxy intercepts → COMMIT 19. MySQL flushes to redo log → releases locks 20. Connection returned to HikariCP pool → L1 cache discarded 21. Controller wraps result → Jackson serialises to JSON 22. Tomcat writes HTTP response → OS sends TCP bytes back 23. Client receives response ✓ I love correlating all applications with kernel, so included sockets. If you want to know in depth correlation then I can mention page cache, fsync, thread life cycle, connection life cycle with port & overall kernel interaction at surface level in above lifecycle sequentially from next time :)
To view or add a comment, sign in
-
🚀 Stop Manual Updates: The Magic of Hibernate Dirty Checking ✔️Ever wondered why your database updates even when you never called .save()? ✔️That’s not a bug; it’s one of Hibernate’s most powerful features. 🎭 The 4 Stages of an Entity’s Life ➡️ Think of Hibernate states as a "VIP Club" for your Java objects. 1️⃣. Transient (The Outsider) ✔️ The object is just a regular Java object. Hibernate doesn't even know it exists. ✔️It has no ID and no connection to the database. ✔️Example: User user = new User("JavaDev"); ✔️Just sitting in your RAM, minding its own business. 2️⃣. Persistent (The VIP Member) ✔️You’ve called .save() or .persist(). The object is now "Managed." ✔️Hibernate is officially "watching" every single change you make to this object. ✔️Example:session.save(user); ✔️Hibernate now tracks this user in its internal cache. 3️⃣. Detached (The Former Member) ✔️The Session is closed. ✔️ The object still has its data and its Database ID, but the "link" is broken. ✔️Hibernate has stopped watching. ✔️Example: session.close(); ✔️ If you change user.setName() now, nothing happens in the database. 4️⃣. Removed (The Evicted) ✔️The object is scheduled to be deleted. ✔️It’s still in your code for a moment, but it’s headed for the exit. ✔️Example: session.delete(user); ✔️ It will be wiped from the DB once the transaction commits. ✨ The "Dirty Checking" Secret ✔️Dirty Checking is the reason you can write cleaner code. ✔️When an object is in the Persistent state, Hibernate takes a "snapshot" of it. ✔️When the transaction is about to finish (Commit), Hibernate performs a quick comparison: 🔹Snapshot:Name: "Rahul" 🔹Current Object: Name: "Rahul Kumar" ✔️Hibernate detects the "Dirt": Aha! The name changed. I’ll handle the SQL update for you! 💡 Why should you care? 1️⃣.Cleaner Code: Your methods aren't cluttered with unnecessary .save() calls. 2️⃣. Performance:Hibernate is smart; if nothing actually changed (no "dirt" found), it won't even fire the SQL update. 3️⃣.Consistency:It ensures your Java memory and Database stay in perfect sync. ✔️What’s your favorite "hidden" Hibernate feature? Let’s discuss in the comments! 👇 #Java #Hibernate #SpringBoot #BackendDevelopment #CodingTips
To view or add a comment, sign in
-
-
Running native queries in Spring? Hibernate's L2 cache doesn't know about native queries. When you bypass JPQL and fire raw SQL directly, Hibernate has no way to track the changes made. The stale data quietly stays in the cache. The fix: clearAutomatically = true on @Modifying @Query( value = "UPDATE products SET price = :price WHERE id = :id", nativeQuery = true ) @Modifying(clearAutomatically = true) @Transactional int updatePrice(@Param("price") BigDecimal price, @Param("id") Long id); This evicts the entire persistence context (L1 cache) after the bulk update. So the next read goes back to the DB. Real-world scenarios where this matters: 1) Bulk price updates in e-commerce (without clear, the old price is returned) 2) Soft deletes via native UPDATE (cached entity still shows as "active") 3) Batch status/audit flag changes (stale flags break downstream logic silently) 4) In-app data migrations running native DML during startup or scheduled jobs Advantages: 1) Prevents stale reads after bulk DML 2) Keeps L1 cache consistent with DB state 3) Zero boilerplate - one annotation flag Disadvantages: 1) Evicts the entire persistence context - not just the affected rows 2) Triggers an implicit flush before eviction (can surface unexpected dirty checks) 3) Hurts performance in large, long-running transactions 4) Does not invalidate L2 cache (Ehcache, Redis) - handle that separately Note: Use clearAutomatically = true whenever native bulk DML touches data already loaded in your persistence context. For L2 cache invalidation, pair it with @CacheEvict or a manual eviction call. #Java #SpringBoot #SpringDataJPA #Hibernate #SoftwareEngineering
To view or add a comment, sign in
-
🚀 Day 85 – Building a Spring + Hibernate CRUD Application Hello everyone, I’m Nagu Mulampaka, currently learning Java Full Stack Development, and I’m excited to share that I recently built a Spring and Hibernate project to manage employee data. This project was a key step in my learning, helping me understand real-world application design using layered architecture, ORM frameworks, and Spring features. 🔍 Overview I developed a Java-based backend application that performs complete CRUD operations (Create, Read, Update, Delete) on employee records stored in a MySQL database. It demonstrates how modern Java applications use frameworks like Spring and Hibernate to simplify development and improve maintainability. Key Concepts Learned and Implemented: 1️⃣ Entity Layer (Model Design): ● Created an Employee class mapped to a database table using JPA annotations (@Entity, @Table, @Id, @Column). ● Encapsulated fields like id, empname, address, contact, and experience. ● Followed proper Java Bean conventions with constructors, getters, and setters. 2️⃣ DAO Layer (Data Access Layer): ● Defined EmployeeDao interface to declare database operations. ● Implemented EmployeeDaoImpl using Spring’s HibernateTemplate. Performed operations like: ✔ Save employee ✔ Update employee ✔ Delete employee ✔ Fetch by ID ✔ Fetch all records ● Used @Transactional to ensure data consistency and transaction safety. This layer manages database operations separately, making the application easy to maintain and update. 3️⃣ Business Layer (Service Layer): ● Implemented EmployeeBusiness and EmployeeBusinessImpl. ● Used @Autowired for dependency injection, allowing loose coupling between layers. 4️⃣ Spring Configuration (Using XML-based Configuration): ✔️ Component Scanning → Automatically detects DAO & Service classes ✔️ DataSource Configuration → Connects application with MySQL database ✔️ SessionFactory → Integrates Hibernate with Spring ✔️ Hibernate Properties → Dialect, SQL logging ✔️ HibernateTemplate → Simplifies ORM operations ✔️ Transaction Manager → Handles transactions using @Transactional 5️⃣ Main Application (App.java) – Entry Point of the System In my Spring + Hibernate application, the App.java class serves as the starting point of the application. It is responsible for initializing the application, loading the Spring configuration, and executing business operations such as: ✔ Inserting employee records ✔ Updating employee details ✔ Deleting records ✔ Fetching and displaying all employees ➤ Core Concepts I Strengthened ● Object-Relational Mapping (ORM) with Hibernate ● Understanding the difference between Hibernate and JDBC ● Transaction Management using @Transactional ● Real-world CRUD operations implementation 👉 GitHub Repository: https://lnkd.in/g8ZnJCyg #Java #SpringFramework #Hibernate #FullStackDeveloper #BackendDevelopment #MySQL #Maven #LearningJourney #SoftwareEngineering #DailyLearning #OpenToWork 🚀
To view or add a comment, sign in
-
I spent weeks writing SQL by hand. Then I met Hibernate. Then Spring Boot. Now I can’t go back. Here’s what changed 👇 Raw JDBC → Hibernate → Spring Boot Data JPA It’s not just “less code.” It’s a completely different mental model. What Hibernate gave me: No more raw SQL for basic operations. You write Java. Hibernate translates. session.persist(empleado); // INSERT session.merge(empleado); // UPDATE session.remove(empleado); // DELETE Zero SQL written by hand. ✅ HQL lets you query objects, not tables. It felt like a superpower. Then Spring Boot Data JPA walked in. empleadoRepository.save(empleado); empleadoRepository.findById(id); empleadoRepository.deleteById(id); That’s it. No SessionFactory. No transaction boilerplate. No session.close(). Spring manages it all. So when does each one make sense? 🔹 Raw JDBC — when you need full control, complex custom queries, or you’re working in a legacy codebase. Not glamorous, but powerful. 🔹 Hibernate (standalone) — when you want ORM without a full framework. Great for learning the fundamentals before Spring. 🔹 Spring Boot + JPA — for real-world apps where speed and maintainability matter. This is what most companies actually use. ⚠️ The traps nobody warns you about: • Spring Boot hides so much — if you skip Hibernate basics, you won’t understand why things break • N+1 query problem: fetching a list of entities that each trigger extra queries = silent performance killer • Lazy loading outside a transaction = LazyInitializationException (classic first-week Spring error) • @Transactional is not optional — forget it and your data won’t save when you think it will The magic is real. But the magic has rules. Learn Hibernate first. Then let Spring Boot automate it. Building this in IntelliJ with Java — and every topic feels like unlocking a new level 🎮 hashtag #Java hashtag #Hibernate hashtag #SpringBoot hashtag #JPA hashtag #DesarrolloBackend hashtag #DAM
To view or add a comment, sign in
-
-
Really interesting perspective on the trade-offs between Spring Data JPA and JDBC. In my experience working with backend systems, this balance between abstraction and control is always a challenge. While ORMs like JPA make development faster, they can sometimes hide what’s really happening at the SQL level, especially when dealing with performance issues. Tools like jOOQ are interesting because they give you more control over queries while still keeping the benefits of type safety and integration with Java. I think the key is choosing the right tool based on the problem—especially when performance and complex queries are involved. Curious to hear—have you used jOOQ in production, and how was your experience?
💡 Java Object-Oriented Querying. 👉 In terms of database access, the Java community is clearly divided into two camps: some like Spring Data JPA for its simplicity and low entry threshold. In contrast, others prefer Spring JDBC for its accuracy and query-tuning capabilities. 👉 Both Spring Data JPA and Spring Data JDBC, with their obvious advantages, have disadvantages that make development on them not very suitable for production. These solutions are two extremes, and we need a golden mean. 🔥 You may ask: What are the alternatives? And I will answer: Java Object-Oriented Querying. ⚠️ jOOQ (Java Object-Oriented Querying) is a Java library that allows you to write SQL queries directly in your code using a typed DSL (Domain-Specific Language) generated based on the database schema. When used with Spring Boot, jOOQ provides strong typing, query safety, and convenient database operations, making it an excellent alternative to ORMs like Hibernate for complex queries. 🔥 Unlike Spring Data JPA, jOOQ has no side effects. There is no N+1 problem (unless, of course, you create one yourself with suboptimal queries). All queries will be executed exactly as you define them and in exactly the number you specify. ➕ Benefits: ▪️ Code generation: jOOQ scans your database and generates Java classes corresponding to the tables and views. ▪️ Type safety: If you change a column name in the database, the project will not compile until you update the queries, which prevents runtime errors. ▪️ SQL-oriented: Unlike Hibernate (which hides SQL), jOOQ allows you to write full-fledged, complex SQL queries (JOINs, subqueries, window functions) in Java, while retaining control over what happens. ▪️ Integration with Spring: Spring Boot automatically configures jOOQ components, supporting transactions and mapping results to POJOs (Plain Old Java Objects). 🔥 DSL frameworks solve the problem of “translation” between Java and SQL, allowing you to write a database query in a Java-based architecture in such a way that it exactly matches the expected SQL query. ‼️ Examples: Result<Record> result = create..select() .from(AUTHOR) .where(AUTHOR..ID..gt(5)) .orderBy(AUTHOR..FIRST_NAME..asc()) .fetch(); for (Record r: result) { Integer id = r.getValue(AUTHOR..ID); String firstName = r.getValue(AUTHOR.FIRST_NAME); logger.log(Level..INFO, "ID: {}, Name: {}", id, firstName); } 📌 jOOQ is the perfect choice if you need full control over SQL but want to avoid manual JDBC data mapping and typos in SQL queries. #programmingtips #softwaredevelopment #data #spring
To view or add a comment, sign in
-
-
Understanding the N+1 Problem in Hibernate & Spring Data JPA A single line of code accessing a lazy association inside a loop can silently generate thousands of database queries in production. This is the N+1 problem — and it is one of the most common performance killers in Hibernate and Spring Data JPA. 🚨 ⚠️ What Is the N+1 Problem It occurs when ORM generates additional queries beyond the initial fetch. 🔹 1 query fetches the parent records — Orders. 🔹 N separate queries fetch child records — Items per Order. 🔹 Total database round trips = N+1 instead of 1. 🔹 At 10 records — negligible impact. 🔹 At 10,000 records — connection pool exhaustion and service degradation. The code looks clean. The ORM is working as designed. The database is being hammered. 🔍 Why It Happens The root cause lies in how Hibernate handles association loading by default. 🔹 FetchType.LAZY is the default for all associations. 🔹 Related entities are loaded only when accessed. 🔹 Accessing a lazy field inside a loop triggers one query per iteration. 🔹 The abstraction layer makes this completely invisible in the code. No warning. No exception. Just silent query multiplication at runtime. 🎯 🔥 Production Impact In a real service returning order summaries via a REST API: 🔹 Staging environment — 50 records, 51 queries, undetected 🔹 Production dataset — 8,000+ orders with multiple items each. 🔹 Single API call generating 8,000+ SQL queries. 🔹 Database CPU spiked — HikariCP connection pool exhausted. 🔹 API response time degraded from 180ms to 14 seconds. 🔹 Downstream service SLAs breached within minutes. Root cause identified only after enabling SQL logging in production. ✅ Solutions and When to Use Each Each approach addresses a different context and data access pattern: 🔹 JOIN FETCH — single query fetching parent and child together, most effective for simple associations. 🔹 @EntityGraph — declarative fetch strategy defined at query time, clean and maintainable. 🔹 @BatchSize — fetches collections in configurable batches, reduces round trips without a full join. 🔹 DTO Projections — fetches only required fields, eliminates entity loading overhead entirely — recommended for API response payloads. Important — switching to FetchType.EAGER is not a solution. It trades N+1 for Cartesian Product explosions and memory overhead when multiple collections are involved. ❌ 💡 Key Takeaways 👉 Any lazy field accessed inside a loop is a guaranteed N+1. 👉 Always enable SQL logging in development — make query behavior visible. 👉 DTO Projections should be the default choice for API response payloads. 👉 Every association requires a deliberate fetch strategy — never rely on defaults. 👉 N+1 does not surface in unit tests — it surfaces at production data volumes. #Hibernate #SpringDataJPA #SpringBoot #Java #BackendDevelopment #PerformanceEngineering #SystemDesign #SoftwareEngineering
To view or add a comment, sign in
-
-
I spent weeks writing SQL by hand. Then I met Hibernate. Then Spring Boot. Now I can’t go back. Here’s what changed 👇 Raw JDBC → Hibernate → Spring Boot Data JPA It’s not just “less code.” It’s a completely different mental model. What Hibernate gave me: No more raw SQL for basic operations. You write Java. Hibernate translates. session.persist(empleado); // INSERT session.merge(empleado); // UPDATE session.remove(empleado); // DELETE Zero SQL written by hand. ✅ HQL lets you query objects, not tables. It felt like a superpower. Then Spring Boot Data JPA walked in. empleadoRepository.save(empleado); empleadoRepository.findById(id); empleadoRepository.deleteById(id); That’s it. No SessionFactory. No transaction boilerplate. No session.close(). Spring manages it all. So when does each one make sense? 🔹 Raw JDBC — when you need full control, complex custom queries, or you’re working in a legacy codebase. Not glamorous, but powerful. 🔹 Hibernate (standalone) — when you want ORM without a full framework. Great for learning the fundamentals before Spring. 🔹 Spring Boot + JPA — for real-world apps where speed and maintainability matter. This is what most companies actually use. ⚠️ The traps nobody warns you about: • Spring Boot hides so much — if you skip Hibernate basics, you won’t understand why things break • N+1 query problem: fetching a list of entities that each trigger extra queries = silent performance killer • Lazy loading outside a transaction = LazyInitializationException (classic first-week Spring error) • @Transactional is not optional — forget it and your data won’t save when you think it will The magic is real. But the magic has rules. Learn Hibernate first. Then let Spring Boot automate it. Building this in IntelliJ with Java — and every topic feels like unlocking a new level 🎮 #Java #Hibernate #SpringBoot #JPA #DesarrolloBackend #DAM
To view or add a comment, sign in
-
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