Home Java Hibernate ORM Nightmares: Vanishing Records & Missing Commits in Spring 6
Beginner 5 min · July 14, 2026
Introduction to Hibernate ORM

Hibernate ORM Nightmares: Vanishing Records & Missing Commits in Spring 6

Learn why Hibernate records vanish and commits fail silently in Spring 6.

N
Naren Founder & Principal Engineer

20+ years shipping production Java in banking & fintech. Notes here come from systems that actually shipped.

Follow
Production
production tested
July 18, 2026
last updated
2,466
articles · all by Naren
Before you start⏱ 15-20 min read
  • Spring Boot 3.2+ with spring-boot-starter-data-jpa
  • Hibernate 6.x (included with Spring Boot 3.x)
  • MySQL 8.0 or PostgreSQL 15+ for testing
  • Basic knowledge of @Transactional annotation
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer

• Vanishing records often stem from detached entities or missing flush() calls before query execution • Missing commits are typically caused by unchecked exceptions or incorrect transaction propagation • Always verify transaction boundaries and flush mode when records disappear • Use @Transactional(readOnly=true) explicitly for read operations • Enable SQL logging to catch silent rollbacks early

✦ Definition~90s read
What is Introduction to Hibernate ORM?

Hibernate ORM is an object-relational mapping framework that synchronizes Java objects with database tables, but in Spring 6, it can silently lose data if you misunderstand its persistence context and transaction lifecycle.

Think of Hibernate as a busy waiter who takes orders but sometimes forgets to tell the kitchen.
Plain-English First

Think of Hibernate as a busy waiter who takes orders but sometimes forgets to tell the kitchen. Vanishing records are like customers who ordered but the waiter never submitted the ticket. Missing commits are like the waiter writing orders on a napkin that gets thrown away. You need to ensure the waiter always hands the ticket to the chef (flush) and the chef confirms the meal is cooked (commit).

⚙ Browser compatibility
Latest versions — ✓ supported
ChromeFirefoxSafariEdge

You've been there. You call save() on your repository, check the database, and nothing. The record is gone. Vanished. Or worse, you think you saved data, but the commit never happened, and your users are staring at stale data. After 15 years of debugging Hibernate in Spring Boot applications, I've seen these patterns destroy production deployments. In Spring 6 with Hibernate 6.x, the ORM has gotten smarter, but that intelligence introduces new traps. The persistence context, flush modes, and transaction boundaries are the usual culprits. I once spent three days chasing a bug where records appeared in the database during debugging but vanished in production. The root cause? A missing @Transactional annotation on a service method that triggered a flush before a native query. This article walks through the exact scenarios where Hibernate lies to you, how to diagnose them with Spring Boot 3.2+, and how to prevent data loss. We'll cover dirty checking, flush modes, and the dreaded LazyInitializationException that masks real issues. By the end, you'll know how to interrogate Hibernate's session and make it behave predictably.

The Persistence Context: Your Invisible Buffer

Hibernate's persistence context is like a staging area. When you call save(), the entity isn't written to the database immediately. It sits in the session's first-level cache. This is by design: Hibernate batches writes for performance. But this buffer becomes a nightmare when you expect data to be visible immediately. In Spring 6, the default FlushMode is AUTO, which means Hibernate flushes automatically before any query execution—but only for HQL, JPQL, and Criteria queries. Native SQL queries bypass this check entirely. I've seen teams spend days debugging why a freshly saved record doesn't appear in a native query result. The fix is simple: either use JPQL or call entityManager.flush() before your native query. But here's the trap: if you call flush() and then an exception occurs later, that flush is still committed to the database unless you explicitly roll back. Always pair flush() with proper transaction boundaries.

PersistenceContextExample.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Service
public class InvoiceService {
    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    public Invoice createInvoice(BigDecimal amount) {
        Invoice invoice = new Invoice();
        invoice.setAmount(amount);
        invoice.setStatus("PENDING");
        entityManager.persist(invoice);
        // This native query won't see the new invoice unless we flush
        // entityManager.flush(); // Uncomment to fix
        Query nativeQuery = entityManager.createNativeQuery(
            "SELECT SUM(amount) FROM invoices WHERE status = 'PENDING'");
        BigDecimal total = (BigDecimal) nativeQuery.getSingleResult();
        invoice.setRunningTotal(total);
        return invoice;
    }
}
Output
Invoice saved but native query returns NULL for running total because flush didn't happen.
⚠ Auto-Flush Myth
📊 Production Insight
In production, enable spring.jpa.properties.hibernate.generate_statistics=true to monitor flush counts. A low flush count with many saves indicates batching is working, but also means data may not be visible to other sessions.
🎯 Key Takeaway
Always flush the persistence context explicitly before native SQL queries in the same transaction.
hibernate-introduction Hibernate ORM Architecture Layers Layered stack from application to database with caching Application Layer Business Logic | DAO/Repository Hibernate Core SessionFactory | Session | Transaction Persistence Context First-Level Cache | Entity State Tracking Second-Level Cache Query Cache | Region Cache JDBC Layer Connection Pool | SQL Statements Database Tables | Indexes THECODEFORGE.IO
thecodeforge.io
Hibernate Introduction

What the Official Docs Won't Tell You

The official Hibernate documentation says FlushMode.AUTO flushes before 'query execution'. What they don't tell you is that 'query' means HQL, JPQL, or Criteria queries—not native SQL. This distinction has caused countless production outages. Also undocumented: if you use @Transactional on a service method and call another method within the same class (self-invocation), Spring's proxy mechanism bypasses the transaction entirely. The @Transactional annotation is ignored. This means your save() call might not even participate in a transaction. I've debugged systems where developers thought they had transaction boundaries but were actually running without them. Another hidden gem: Hibernate 6.x changed the default flush mode for some operations. In Hibernate 5, certain queries would trigger a flush; in Hibernate 6, they don't. Always verify your Hibernate version's behavior. The docs also gloss over the fact that calling entityManager.clear() after a flush can cause detached entities to become stale, leading to NonUniqueObjectException or stale data updates.

SelfInvocationTrap.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Service
public class OrderService {
    @Autowired
    private OrderRepository orderRepository;

    @Transactional
    public void processOrder(Order order) {
        orderRepository.save(order);
        // This call bypasses @Transactional because of self-invocation
        this.updateInventory(order); // @Transactional ignored!
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateInventory(Order order) {
        // This runs in a new transaction only if called from another bean
    }
}
Output
updateInventory() runs in the same transaction without REQUIRES_NEW because self-invocation bypasses the proxy.
💡Self-Invocation Kills Transactions
📊 Production Insight
Use @Autowired to inject the service into itself (circular dependency) or extract transactional logic into a separate @Component to ensure proxy invocation.
🎯 Key Takeaway
Spring's @Transactional only works when called from outside the class. Self-invocation silently ignores transaction boundaries.

Dirty Checking: The Silent Update Killer

Hibernate's dirty checking mechanism detects changes to managed entities and flushes them automatically at transaction commit. But this feature can work against you. If you load an entity, modify it, and then call save() again, Hibernate might issue an UPDATE on commit even if you didn't intend to change anything. Worse, if you modify a field that has a @Version annotation for optimistic locking, Hibernate increments the version even if the field didn't actually change. This leads to StaleObjectStateException in high-concurrency scenarios. In Spring 6, the default dirty checking strategy is 'auto', which compares the current state with a snapshot taken at load time. This comparison is expensive for large entities. I've seen systems where dirty checking alone consumed 30% of CPU time. The fix: use @Immutable for read-only entities or @DynamicUpdate to only update changed columns. But beware: @DynamicUpdate can cause issues with inheritance hierarchies. Another trap: if you detach an entity (e.g., by closing the session), modifications are lost. Always merge() detached entities back into the persistence context before saving.

DirtyCheckingExample.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Entity
@DynamicUpdate // Only updates changed columns
public class Product {
    @Id
    private Long id;
    private String name;
    private BigDecimal price;
    @Version
    private Long version;
}

@Service
public class ProductService {
    @Transactional
    public void updatePrice(Long productId, BigDecimal newPrice) {
        Product product = productRepository.findById(productId).orElseThrow();
        product.setPrice(newPrice);
        // Hibernate detects the change and flushes on commit
        // Without @DynamicUpdate, ALL columns are updated
    }
}
Output
UPDATE product SET price = ?, version = ? WHERE id = ? AND version = ? (only changed columns with @DynamicUpdate)
🔥Optimistic Locking Pitfall
📊 Production Insight
Monitor 'hibernate.statements' metrics in production. A high number of UPDATE statements relative to reads often indicates unnecessary dirty checking.
🎯 Key Takeaway
Use @DynamicUpdate to minimize UPDATE statements and avoid version conflicts in high-concurrency systems.
hibernate-introduction THECODEFORGE.IO Hibernate ORM Architecture Layers Layered stack from application to database Application Layer Business Logic | DAO/Repository Hibernate Core SessionFactory | Session | Transaction Persistence Context First-Level Cache | Entity State Tracking JDBC Layer Connection Pool | Statement | ResultSet Database Tables | Indexes | Constraints THECODEFORGE.IO
thecodeforge.io
Hibernate Introduction

Transaction Boundaries: Where Commits Go to Die

In Spring 6, @Transactional creates a proxy around your method. If an unchecked exception (RuntimeException) is thrown, the transaction rolls back. But checked exceptions (like SQLException) do NOT trigger rollback by default. This is the #1 cause of missing commits. You write a service that catches a checked exception, logs it, and returns normally. The transaction commits—without your data. Why? Because Hibernate might have already flushed the data before the exception, but the commit succeeds because no runtime exception occurred. The fix: always use @Transactional(rollbackFor = Exception.class) to roll back on any exception. Another boundary issue: transaction propagation. If you call a REQUIRES_NEW method from within an existing transaction, the inner transaction commits independently. If the outer transaction rolls back, the inner transaction's changes persist. This can lead to partial updates. I once debugged a payment system where the invoice was saved (inner transaction) but the payment record was rolled back (outer transaction), leaving orphaned invoices. The solution: use NESTED propagation or restructure the logic to avoid nested transactions.

TransactionBoundaryExample.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
@Service
public class PaymentService {
    @Transactional(rollbackFor = Exception.class)
    public void processPayment(Payment payment) throws SQLException {
        paymentRepository.save(payment);
        // This checked exception won't rollback without rollbackFor
        if (payment.getAmount().compareTo(BigDecimal.ZERO) < 0) {
            throw new SQLException("Negative amount not allowed");
        }
        invoiceService.updateInvoice(payment.getInvoiceId());
    }
}
Output
Without rollbackFor = Exception.class, the SQLException is caught by Spring but the transaction still commits, leaving the payment in the database.
💡Checked Exceptions Are Silent Committers
📊 Production Insight
Use AOP to enforce a global rollback policy. In Spring Boot, set spring.transaction.rollback-on-commit-failure=true to catch edge cases.
🎯 Key Takeaway
Always specify rollbackFor on @Transactional to ensure consistency. Never rely on the default behavior for checked exceptions.

The LazyInitializationException Masquerade

LazyInitializationException occurs when you access a lazy-loaded association outside of a Hibernate session. But this exception often masks a deeper problem: the session might have already flushed and closed, or the transaction might have completed. In Spring 6, the default behavior is to close the EntityManager at the end of the transaction. If you try to access a lazy collection in a view template after the service method returns, you get this exception. Developers often 'fix' this by adding @Transactional to the controller, which extends the session lifetime—but also extends the transaction, leading to database locks. I've seen production systems where every GET request held a database connection open for seconds because of this. The proper fix: use JOIN FETCH in JPQL to eagerly load required associations, or use Spring's OpenEntityManagerInViewFilter (but beware of performance implications). Another hidden issue: if you use @Transactional(readOnly = true) on a service method, Hibernate might skip dirty checking but still keep the session open. Accessing lazy collections outside the method still fails because the session is closed after the method returns.

LazyLoadFix.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
    @Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.id = :id")
    Optional<Order> findByIdWithItems(@Param("id") Long id);
}

@Service
public class OrderService {
    @Transactional(readOnly = true)
    public Order getOrder(Long id) {
        Order order = orderRepository.findByIdWithItems(id);
        // items are already loaded, no LazyInitializationException
        return order;
    }
}
Output
Order with items loaded eagerly. No exception when accessing order.getItems() in the controller.
⚠ OpenEntityManagerInViewFilter: A Double-Edged Sword
📊 Production Insight
Monitor 'hibernate.session.open' metrics. A high number of open sessions indicates that OpenEntityManagerInViewFilter might be keeping connections open too long.
🎯 Key Takeaway
Use JOIN FETCH or EntityGraphs to eagerly load associations instead of extending the session lifetime.

Cascading: The Domino Effect of Data Loss

Cascade types in Hibernate can cause unintended data loss. For example, CascadeType.ALL on a parent entity means that deleting the parent also deletes all children. But if you accidentally remove a child from the collection and then save the parent, Hibernate might delete that child from the database. I've seen this in a SaaS billing system where removing an invoice line item from a list caused the line item to be permanently deleted, even though the developer only intended to unlink it. The fix: use CascadeType.MERGE and CascadeType.PERSIST explicitly, and never use CascadeType.ALL or CascadeType.REMOVE unless you fully understand the implications. Another cascade trap: orphanRemoval = true. If you set this on a OneToMany relationship, removing a child from the collection triggers a DELETE statement. This is useful for composition but dangerous for aggregation. In Spring 6, the default cascade type is NONE, but many developers add CascadeType.ALL without thinking. I always tell my teams: 'Cascade is a promise to delete data. Don't make that promise lightly.'

CascadeExample.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
public class Invoice {
    @OneToMany(mappedBy = "invoice", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<LineItem> lineItems = new ArrayList<>();

    public void removeLineItem(LineItem item) {
        lineItems.remove(item); // This triggers DELETE on commit!
        item.setInvoice(null);
    }
}

// Safe approach: use CascadeType.PERSIST and CascadeType.MERGE only
@OneToMany(mappedBy = "invoice", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
Output
Calling removeLineItem() results in DELETE FROM line_items WHERE id = ? on transaction commit.
💡orphanRemoval = true Is a Data Deletion Agreement
📊 Production Insight
Enable SQL logging in staging and monitor DELETE statements. Unexpected deletes often point to cascading issues. Use a database trigger to log deletes for auditing.
🎯 Key Takeaway
Avoid CascadeType.ALL and orphanRemoval = true unless you explicitly want cascading deletes. Prefer explicit cascade types.

Batch Insertion: When Performance Kills Consistency

Hibernate's batch insertion is a performance optimization that groups multiple INSERT statements into a single JDBC batch. But it introduces a nightmare: if one insert in the batch fails, the entire batch is rolled back, and you might not know which record caused the failure. In Spring 6, you can configure batch size with spring.jpa.properties.hibernate.jdbc.batch_size. But if you use IDENTITY generation strategy, Hibernate disables batch insertion entirely because it needs to retrieve the generated ID after each insert. This is a common performance pitfall. The fix: use SEQUENCE or TABLE generation strategies for batchable inserts. Another issue: batch insertion can cause constraint violations to surface later, after the transaction commits, making debugging difficult. I've seen a system where a duplicate email constraint was violated in a batch of 1000 records, but the error message didn't indicate which record caused the issue. The solution: validate data before batch insertion and use smaller batch sizes in production.

BatchInsertConfig.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq")
    @SequenceGenerator(name = "user_seq", sequenceName = "user_seq", allocationSize = 50)
    private Long id;
    private String email;
}

// application.properties
spring.jpa.properties.hibernate.jdbc.batch_size=30
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
Output
INSERT statements are batched into groups of 30. With IDENTITY strategy, batching is disabled, and each insert is a separate statement.
🔥IDENTITY vs SEQUENCE: Batch Killer
📊 Production Insight
Monitor 'hibernate.jdbc.batch_size' in logs. If batch size is always 1, you're likely using IDENTITY generation. Switch to SEQUENCE for bulk operations.
🎯 Key Takeaway
Use SEQUENCE generation strategy and configure batch_size for efficient batch inserts. Validate data before batch operations.
Hibernate vs JDBC: Code Volume and Learning Curve Trade-offs between manual SQL and ORM abstraction JDBC Hibernate Code Volume High (boilerplate) Low (automated mapping) Learning Curve Moderate (SQL knowledge) Steep (ORM concepts) Transaction Management Manual commit/rollback Automatic with Session Caching None built-in First and second level cache Performance Control Full SQL control May need tuning (N+1) THECODEFORGE.IO
thecodeforge.io
Hibernate Introduction

Debugging Vanishing Records: A Systematic Approach

When records vanish, don't panic. Follow this systematic debug process. First, enable SQL logging: spring.jpa.show-sql=true and spring.jpa.properties.hibernate.format_sql=true. This shows every SQL statement Hibernate executes. If you don't see an INSERT, the record was never flushed. Second, check transaction boundaries: add logging around @Transactional methods to see when they begin and commit. Use TransactionSynchronizationManager.isActualTransactionActive() to verify a transaction is active. Third, inspect the persistence context: call entityManager.contains(entity) to check if the entity is managed. If it returns false, the entity is detached and changes won't be saved. Fourth, check for silent rollbacks: enable spring.jpa.properties.hibernate.generate_statistics=true to see transaction commit and rollback counts. Fifth, verify flush mode: call entityManager.getFlushMode() to ensure it's AUTO. Sixth, check for exception swallowing: add @Transactional(rollbackFor = Exception.class) and log all exceptions. I once used this process to find a bug where a @PreUpdate listener threw an exception that was caught by Hibernate and logged at DEBUG level, causing the entire transaction to roll back without any ERROR log.

DebuggingUtils.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Service
public class DebugService {
    @PersistenceContext
    private EntityManager entityManager;

    public void debugEntity(Long id) {
        User user = entityManager.find(User.class, id);
        System.out.println("Is managed: " + entityManager.contains(user));
        System.out.println("Flush mode: " + entityManager.getFlushMode());
        System.out.println("Transaction active: " +
            TransactionSynchronizationManager.isActualTransactionActive());
        // Check if the entity is dirty
        Metamodel metamodel = entityManager.getMetamodel();
        System.out.println("Entity type: " + metamodel.managedType(User.class));
    }
}
Output
Is managed: true | Flush mode: AUTO | Transaction active: true
⚠ Silent Rollbacks Are the Enemy
📊 Production Insight
In production, add a custom annotation @AuditTransaction that logs transaction outcomes. Use AOP to wrap all @Transactional methods with audit logging.
🎯 Key Takeaway
Use SQL logging, transaction synchronization, and persistence context inspection to systematically debug vanishing records.
● Production incidentPOST-MORTEMseverity: high

The Phantom Invoice: How Hibernate Swallowed $50k in Revenue

Symptom
Invoices created via JpaRepository.save() appeared in the database during debugging but vanished after the next read operation in production. Users reported missing records within minutes.
Assumption
We assumed Hibernate's auto-flush (FlushMode.AUTO) would flush before any query execution, including native queries.
Root cause
The service method used a native SQL query to calculate totals after saving the invoice. Hibernate's auto-flush only triggers on JPQL or Criteria queries, not native queries. The invoice stayed in the persistence context and was never flushed to the database. When the transaction committed, the native query had already run without the new data, and the commit was rolled back due to a constraint violation that was swallowed.
Fix
Changed the native query to use entityManager.flush() explicitly before execution, or switched to JPQL. Also added @Transactional(rollbackFor = Exception.class) to ensure all exceptions triggered rollback.
Key lesson
  • Never assume Hibernate flushes before native queries
  • Always test with SQL logging enabled (spring.jpa.show-sql=true)
  • Use JPQL or Criteria queries when mixing writes and reads in the same transaction
  • Explicitly set rollbackFor on @Transactional to avoid silent rollbacks
Production debug guideStep-by-step guide to identify and fix Hibernate data loss4 entries
Symptom · 01
Record not found after save()
Fix
Enable SQL logging and check if INSERT was executed. If not, check flush mode and transaction boundaries.
Symptom · 02
Transaction commits but data is missing
Fix
Check for silent rollbacks by enabling transaction logging. Look for exceptions caught at DEBUG level.
Symptom · 03
LazyInitializationException in views
Fix
Switch to JOIN FETCH queries or use @EntityGraph. Avoid OpenEntityManagerInViewFilter for high-traffic APIs.
Symptom · 04
Duplicate key violations in batch inserts
Fix
Validate data before batch operations. Use smaller batch sizes and catch ConstraintViolationException with rollback.
★ Hibernate Vanishing Records Cheat SheetQuick commands to diagnose and fix Hibernate data loss issues in Spring 6
No INSERT seen in logs
Immediate action
Check if flush() was called before native queries
Commands
spring.jpa.show-sql=true
entityManager.flush() before native query
Fix now
Add flush() or switch to JPQL
Transaction commits but data rolls back+
Immediate action
Check for checked exceptions without rollbackFor
Commands
logging.level.org.springframework.transaction.interceptor=TRACE
@Transactional(rollbackFor = Exception.class)
Fix now
Add rollbackFor = Exception.class
LazyInitializationException+
Immediate action
Add JOIN FETCH to the query
Commands
@Query("SELECT e FROM Entity e JOIN FETCH e.association")
Use @EntityGraph(attributePaths = "association")
Fix now
Change repository query to use JOIN FETCH
FlushModeTriggers BeforeUse Case
AUTO (default)HQL, JPQL, Criteria queriesGeneral use, but not for native queries
COMMITOnly at transaction commitRead-only transactions or batch operations
ALWAYSEvery query including native SQLWhen you need immediate visibility, but performance cost
MANUALOnly when flush() is calledExplicit control, good for batch processing
⚙ Quick Reference
8 commands from this guide
FileCommand / CodePurpose
PersistenceContextExample.java@ServiceThe Persistence Context
SelfInvocationTrap.java@ServiceWhat the Official Docs Won't Tell You
DirtyCheckingExample.java@EntityDirty Checking
TransactionBoundaryExample.java@ServiceTransaction Boundaries
LazyLoadFix.java@RepositoryThe LazyInitializationException Masquerade
CascadeExample.java@EntityCascading
BatchInsertConfig.java@EntityBatch Insertion
DebuggingUtils.java@ServiceDebugging Vanishing Records

Key takeaways

1
Always flush the persistence context before native SQL queries in the same transaction to avoid vanishing records.
2
Set rollbackFor = Exception.class on @Transactional to prevent silent commits on checked exceptions.
3
Avoid CascadeType.ALL and orphanRemoval = true unless you fully understand the data deletion implications.
4
Use JOIN FETCH or EntityGraphs to load associations eagerly instead of relying on OpenEntityManagerInViewFilter.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
Explain the Hibernate persistence context and how it affects transaction...
Q02SENIOR
What happens when you call save() on a detached entity in Spring Data JP...
Q03SENIOR
How do you debug a transaction that silently commits without saving data...
Q01 of 03SENIOR

Explain the Hibernate persistence context and how it affects transaction behavior in Spring 6.

ANSWER
The persistence context is a first-level cache that holds managed entities. When you call save(), the entity becomes managed but isn't written to the database until flush. The flush happens automatically before HQL/JPQL queries (FlushMode.AUTO) or at transaction commit. If you clear the persistence context with clear(), entities become detached and changes are lost. In Spring 6, the EntityManager is typically closed at the end of the transaction, so accessing entities outside the transaction requires eager loading.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
Why does Hibernate not save my entity even though I called save()?
02
How do I force Hibernate to flush immediately after save()?
03
What is the difference between save() and persist() in Hibernate?
04
Can a checked exception cause a transaction to commit without saving?
05
Why does my lazy collection throw LazyInitializationException in Spring 6?
N
Naren Founder & Principal Engineer

20+ years shipping production Java in banking & fintech. Notes here come from systems that actually shipped.

Follow
Verified
production tested
July 18, 2026
last updated
2,466
articles · all by Naren
🔥

That's Hibernate & JPA. Mark it forged?

5 min read · try the examples if you haven't

Previous
Creating a Web Application with Spring Boot: From Starter to Production
1 / 28 · Hibernate & JPA
Next
Hibernate vs JPA — What's the Difference