Build1 distinct publisher3 min readUpdated
A dev.to chapter argues the save-then-findById test never touches the table, and pushes flush-and-clear down into a test-scope DAO proxy so that a pass means persistence.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
The prescription has two steps and only the second one does the work that the test name promises. Flushing pushes the write-behind queue at the database, which is the moment a strict column constraint finally gets consulted [10]. But a flushed entity is still managed and still sitting in the identity map, so the next findById is still answered from memory [1][2]. Clearing the persistence context is the step that forces a fresh entity graph to be hydrated from rows [16].
Look at what the sample assertions can actually fail on. The test checks that the loaded object is not null and that its name is "Gaming Laptop" [6]. Both of those are properties of the Java object the test constructed a line earlier, and that object is what find() returns [2][5]. The pass signal is decoupled from the database contents [15].
The author is careful about the blast radius, and that carefulness is the useful part. Custom JPQL and native @Query methods issue real SQL whether or not the entity is managed, so those tests do reach the dialect [7]. The exposure is confined to the find() path, which is also the path a CRUD suite leans on hardest, because it is the one that takes the least code to write [8]. That is the uncomfortable ordering: the cheapest repository test to write is the one whose green tells you least.
Of the three failure modes named, a strict column constraint, a broken mapping, and a query that only breaks against a real dialect, none can be observed without SQL reaching the database [9]. A save-then-findById test in a single persistence context issues none [5], so its detection rate against that set is zero [14].
Pushing the flush and clear into infrastructure is a bet about human behaviour rather than about Hibernate: per-method boilerplate is what gets dropped under deadline pressure, so the discipline goes into a test-only proxy that wraps every DAO and forces the sequence after any write [11][12]. The boundary is physical rather than conventional. The proxy lives in TestConfig under src/test/java, cannot be reached from production code, and never ships in a production artifact, with production wiring injecting the unproxied DAOs so write-behind batching survives outside tests [13].
The production half of the argument is one practitioner's account. Writing in Chapter 7 of the Evolutionary Architecture series on dev.to [17], the author says he has watched teams ship confidently on tests that only ever validated first-level cache state, until a missing constraint violation or a column mapping bug surfaced in production because the data was never flushed and re-hydrated [4]. No teams are named and no incident count is given. The mechanism, though, does not need his anecdote to be checked: drop a clear into an existing save-then-load test and the assertions that were riding on the object reference are the ones that break [1][2][16].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
Calling find(), which is what Spring Data's derived findById resolves to, for an entity that is already managed causes Hibernate to ask the database nothing and hand back the object it already holds.
A green @DataJpaTest cannot tell the difference between verifying that data round-trips through the database and getting the same Java object reference back.
In the sample test, calling loadById immediately after create, inside the @Transactional wrapper the test runs in, does not issue a SELECT; the entity is still in the L1 cache and find() short-circuits to it, so the table itself never answered a query.
A strict column constraint, a broken mapping, and a query that only breaks against a real dialect can all hide behind a green checkmark in such a test.
Every EntityManager keeps a first-level cache, an identity map of every entity it has touched in the current persistence context.
The sample test creates a Product("A1", "Gaming Laptop", 1500), calls productDao.create, then loadById, and asserts the loaded entity is not null and that its name equals "Gaming Laptop".
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Mechanism well shown, consequences asserted
The core technical claim is demonstrated rather than merely asserted: the article names the identity-map mechanism, shows the exact test that passes vacuously, walks the create/loadById path, and supplies the full proxy implementation including the flush-then-clear ordering. It also self-limits the claim to find()/findById rather than overreaching to all reads. Evidence stops short of higher marks because there is exactly one source and one publisher, no before/after test run proving the pattern flips to red, no reproduction repository, and the impact claims (prevalence of the pattern, real production escapes) are personal assertion with no incident record or measurement.
No adoption signal in supplied sources
The supplied material contains no release, deployment, benchmark, download, star count, pricing or license event, or third-party usage disclosure. The proxy pattern appears only as code inside one authored chapter; whether any team beyond the author uses it is not stated, so no adoption value can be measured without inventing facts.
Mildly overstated framing over sound mechanism
Slightly positive. The technical core is accurate and the author actively deflates his own headline by conceding the gap is 'narrower than all your reads are fake' and limited to find()/findById. Overstatement remains in the framing layer: the pattern's prevalence in CRUD suites, the certainty that hand-written flush-and-clear gets skipped, and the war-story implication that this routinely causes production incidents are all presented with more confidence than the supplied evidence carries. There is also no demonstration that adding flush-and-clear actually surfaces a new failure, so the payoff is argued rather than shown.
Self-published series promoting author's own pattern
Moderate and visible rather than hidden. The piece is self-published on dev.to as Chapter 7 of the author's own Evolutionary Architecture series, and the recommended solution is the author's own abstraction, so there is an interest in framing the default Spring Data test as an 'illusion' to be torn down. There is no vendor sponsorship, product sale, pricing claim, or affiliate relationship in the supplied material, and the code is given away in full, which limits the commercial pull.
Mechanism trustworthy, impact and reach unproven
Confidence is mid-range. What can be checked from the text — the identity-map behavior, the vacuous assertions in the sample test, the flush-then-clear ordering, and the proxy code — is internally consistent and consistent with documented JPA semantics, and the author narrows his own claim. Confidence is limited by structural thinness: one source, one publisher, zero adoption evidence, no reproduction, and the most consequential claims (real production escapes, how widespread the pattern is) resting on unverifiable personal assertion.
build
The @Version field that guarded nothing: JPA counters, bulk UPDATEs and quietly missing clicks1 distinct publisher
build
Shared memory in Java: the mmap is the easy half, the descriptor handoff is the work1 distinct publisher
build
COBOL to Java now has a price tag: £200k to £800k, and the risk is your decimals1 distinct publisher
build
The proxy in your call path decides whether @Transactional does anything at all1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 24, 2026