A long-running `@Transactional` job loads an `Account`, does some work, then re-runs a JPQL query for the same account "to get the latest balance" — the SQL shows in the log — and changes its `status`. Meanwhile another request committed a new balance. After the job commits, that other request's balance change is gone. Explain every step, and how `@Version` changes the outcome.
Three things combine. The re-query did run (the SQL is in the log), but the account was already managed, and the persistence context always hands back the managed instance for a row it already holds, discarding the fresh values the query read. So the job still has the old balance in memory. At flush, dirty checking sees status changed and writes an UPDATE, and Hibernate's default UPDATE sets every mapped column, including the stale balance, so the other request's committed change is overwritten. Nobody gets an error. With a @Version column, Hibernate adds where version = ? with the version it loaded; the other request's commit already bumped it, the UPDATE matches zero rows, and the job fails with ObjectOptimisticLockingFailureException instead of silently erasing someone else's write.