Real World Example

Diagnosing a Slow Order Update

A payments team (think Paytm or Razorpay dashboards) saw "mark order shipped" take 2 seconds. The method loaded the order through a repository method that also pulled 5,000 audit rows into the session, so every AUTO flush dirty-checked thousands of entities. Understanding the internals pointed straight to the fix:

// BEFORE: big persistence context + a query inside a loop triggers repeated AUTO flushes
@Transactional
public void markShipped(List<Long> orderIds) {
    for (Long id : orderIds) {
        Order o = orders.findWithAuditTrail(id);       // loads Order + 5,000 AuditEntry entities
        o.setStatus(OrderStatus.SHIPPED);
        long open = orders.countByStatus(OrderStatus.PACKED);   // query -> AUTO flush -> dirty check ALL
        metrics.gauge("orders.packed", open);
    }
}

// AFTER
@Transactional
public void markShippedFast(List<Long> orderIds) {
    for (List<Long> chunk : Lists.partition(orderIds, 100)) {
        orders.findAllById(chunk)                      // only the orders, no audit trail
              .forEach(o -> o.setStatus(OrderStatus.SHIPPED));
        em.flush();                                    // one batched flush per chunk
        em.clear();                                    // keep the context small
    }
    metrics.gauge("orders.packed", orders.countByStatus(OrderStatus.PACKED));   // once, at the end
}

What Changed

InternalBeforeAfter
Managed entities per flush~5,000+≤ 100
Flushesone per order (AUTO before each count)one per 100 orders
UPDATE statementsnot batchedJDBC batches of 50
Time for 500 orders~2 s each call~180 ms total