Java中while循环内Thread.sleep()后无法获取最新记录问题
Hey there, let's break down why your infinite loop isn't picking up the latest database records and fix it step by step.
Common Causes & Fixes
1. Transaction Isolation Level Locking You to Old Data
Most databases default to the Repeatable Read isolation level. If your loop runs within a single ongoing transaction, it'll keep reading the same snapshot of data—even if other transactions update the StoreHeartbeat record. This is a classic "stale read" issue.
Fix:
Ensure each database query runs in a fresh transaction. If you're using Spring, adjust the transaction propagation for your findByStoreId method to force a new transaction every time:
@Service public class StoreHeartbeatService { @Transactional(propagation = Propagation.REQUIRES_NEW) public StoreHeartbeat findByStoreId(Context context, String locationId) { // Your existing query logic here } }
This way, every call to findByStoreId starts a new transaction, bypasses the old data snapshot, and pulls the latest record from the database.
2. ORM Level Caching (e.g., Hibernate First-Level Cache)
If you're using JPA/Hibernate, the first-level cache (tied to the current Session/EntityManager) caches entities after the first fetch. Subsequent queries in the same Session will return the cached, outdated object instead of hitting the database.
Fixes:
- Refresh the entity after fetching to pull the latest state directly from the database:
storeHeartbeat = storeHeartbeatService.findByStoreId(context, locationId); entityManager.refresh(storeHeartbeat); // Add this if using JPA - The transaction fix above also helps here, as a new transaction will use a fresh Session/EntityManager.
3. Application-Level Caching (e.g., Spring Cache)
If you added a @Cacheable annotation to your findByStoreId method, your app will return cached results instead of querying the database. This is a super common gotcha!
Fix:
- Remove the
@Cacheableannotation if caching isn't needed for this specific query. - If caching is required elsewhere, make sure to evict the cache whenever the StoreHeartbeat record is updated:
@CacheEvict(value = "storeHeartbeatCache", key = "#locationId") public void updateStoreHeartbeat(StoreHeartbeat heartbeat) { // Your update logic here }
Modified Working Loop Example
Here's how your loop might look after applying the transaction and refresh fixes:
// Initial load (ensure this runs in a transaction if needed) StoreHeartbeat storeHeartbeat = storeHeartbeatService.findByStoreId(context, locationId); while (true) { if (storeHeartbeat.getCurrentHeatbeatDatetime().isAfter(jobTriggeredTime)) { break; } TimeUnit.MILLISECONDS.sleep(300000); // Fetch fresh data in a new transaction storeHeartbeat = storeHeartbeatService.findByStoreId(context, locationId); // Optional: Refresh if using JPA to guarantee latest state // entityManager.refresh(storeHeartbeat); }
内容的提问来源于stack exchange,提问作者Balakrishna R

