Tag: Spring
All the articles with the tag "Spring".
-
The Real Cost of JPA Dirty Checking — readOnly, @DynamicUpdate, and Query Plan Cache Leaks
Hibernate's dirty checking copies an entity snapshot at load time and compares it against the current state at flush. With 10,000 rows, readOnly=true skips the snapshot copy (memory savings). @DynamicUpdate emits SQL with only the changed columns — but generates a fresh SQL string per update pattern, increasing Query Plan Cache usage (a permanent heap leak if hibernate.query.plan_cache_max_size is unset). @Modifying bulk JPQL is fastest but leaves the persistence context inconsistent — clearAutomatically=true is the standard. The clear() pattern (flush + clear every 50 inserts) keeps memory bounded for large insert batches. The trap in JPA is never one feature; it is the interaction of flush, cache, and snapshot lifecycle.
-
JPA Optimistic Lock and the Retry Stampede Trap — 6 Scenarios @Version Cannot Cover Alone
100 workers each increment the same rule's priority by +1. Without @Version, the final priority < 100 (Lost Update). With @Version, you only get OptimisticLockException — handling is the caller's responsibility, so only some succeed. @Retryable(3) with backoff=0 produces **retry stampede** — retries pile up at the same instant, colliding again. Exponential backoff with full jitter spreads retries out and reaches priority=100. Plus the **self Lost Update** trap discovered along the way — same transaction, two SELECTs returning different objects (JDBC) vs the same instance (JPA first-level cache `==`). Different category from distributed Lost Update. The piece also covers @Transactional + @Retryable AOP ordering and the AWS Architecture Blog rationale for full jitter.
-
[JPA + Spring Mastery 08] Transaction Split Patterns — Saga / Outbox / REQUIRES_NEW, from academic origins to a 9-scenario EXP-09b measurement
The maxim *don't call external APIs inside a transaction* is well known; the *how* is rarely treated honestly. This article goes from PROPAGATION's seven semantics to 2PC (XA)'s limits, to Garcia-Molina's 1987 Sagas paper, Pat Helland's CIDR 2005 Data on the Outside, and Vogels's ACM Queue 2008 Eventually Consistent — then through Toss SLASH24's SAGA, 29CM and Ridi's Outbox in production — and lands on the EXP-09b 9-scenario measurement matrix (patterns A/B/C × OFF/DB_FAIL/EXT_FAIL). Payments to Saga, notifications to Outbox, cache only to plain split — academic + production + measurement, in three layers.
-
MySQL Credit Deduction — 4 Locks Compared, Pessimistic at 180ms / 100% accurate, plus the self-invocation trap I hit during measurement
An ordinary scenario — 100 workers concurrently subtracting 1 from an account with balance 100. Four lock strategies (optimistic / pessimistic / MySQL GET_LOCK / Redisson) all produce different results — pessimistic 180ms / 100% / balance 0, optimistic 549ms (retry storm under contention), GET_LOCK 5015ms (advisory lock cost), Redisson 53/100 (single-instance limitation). And during measurement I hit the self-invocation trap — successes=100 but the balance never moved. The real Spring/JPA pitfall is not logic, it is AOP proxy bypass. A walkthrough including direct demos of the connection-bound GET_LOCK traps in 4 scenarios.