# Entity States and Dirty Checking — Hibernate / JPA

Source: https://www.skillbyai.com/en/hibernate-jpa/p-states

> Describe transient, managed, detached and removed states and automatic dirty checking.

## Four states of an entity

Every entity instance is in one of four states relative to a persistence context. **Transient (new)**: created with `new`, not yet associated with a persistence context or a database row. **Managed (persistent)**: associated with the current persistence context; Hibernate tracks it. **Detached**: was managed, but the persistence context has closed or the entity was detached, so changes are no longer tracked. **Removed**: scheduled for deletion at the next flush. The most powerful consequence is **automatic dirty checking**: when a transaction flushes, Hibernate compares each managed entity's current state with the **snapshot** taken when it was loaded and issues `UPDATE` statements for changed entities, **without any explicit save call**. The persistence context also acts as a **first-level cache** and **identity map**: within one context, loading the same ID twice returns the same Java object, guaranteeing a single in-memory representation per row. Detached entities, typically objects returned from a service after the transaction ended, must be reattached with `merge` to persist further changes.

## Dirty checking in action

No save call: the change is detected and written at commit.

```java
@Transactional
public void applyDiscount(Long productId, BigDecimal percent) {
    Product p = em.find(Product.class, productId);       // managed; snapshot taken
    BigDecimal factor = BigDecimal.ONE.subtract(percent.movePointLeft(2));
    p.changePrice(p.getPrice().multiply(factor));         // just change the object
}   // commit -> flush -> UPDATE products SET price = ? WHERE id = ?

@Transactional
public void identity(Long id) {
    Product a = em.find(Product.class, id);               // SELECT
    Product b = em.find(Product.class, id);               // no SELECT: first-level cache
    assert a == b;                                         // same Java object
}

public Product loadOutsideTransaction(Long id) {
    return productService.findById(id);                   // returned entity is DETACHED here
    // changing it now will not be saved unless merged in a new transaction
}
```

## A tracked shopping cart

A managed entity is an item in a shop's tracked cart: the shop notices whenever you change the quantity and bills you at checkout. A detached entity is a photocopy of the receipt you took home; scribbling on it changes nothing in the shop's system.

**Quiz:** Inside a transaction, you load an entity and change one field without calling save. What happens at commit?

- [ ] Nothing; changes are lost
- [x] Hibernate detects the change by dirty checking and issues an UPDATE
- [ ] An exception is thrown
- [ ] The entity is deleted

*Answer:* Hibernate detects the change by dirty checking and issues an UPDATE. Managed entities are compared with their snapshot at flush, and changes are written automatically.
