PR Review Lab · Cache User Profiles in Memory

25:00left of 25:00

Cache User Profiles in Memory

The profile endpoint is our most-read route, and every request goes to the database. This adds a map in front of the repository so repeat reads of the same profile skip the query. Locally, p95 for GET /users/{id}/profile dropped from 38 ms to 2 ms. updateProfile now reads straight from the repository so it always edits the latest data.

Msrc/main/java/com/acme/profile/ProfileService.java1 of 2

Files Changed

src/main/java/com/acme/profile/

src/test/java/com/acme/profile/

src/main/java/com/acme/profile/ProfileService.java

Java · Click a line number to comment · Tap a line to comment
@@ -1,26 +1,37 @@
package com.acme.profile;
Added: import java.util.HashMap;
Added: import java.util.Map;
Added:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class ProfileService {
private final ProfileRepository repository;
Added: private final Map<Long, Profile> cache = new HashMap<>();
public ProfileService(ProfileRepository repository) {
this.repository = repository;
}
public Profile getProfile(long userId) {
Removed: return repository.findById(userId)
Added: Profile cached = cache.get(userId);
Added: if (cached != null) {
Added: return cached;
Added: }
Added: Profile profile = repository.findById(userId)
.orElseThrow(() -> new ProfileNotFoundException(userId));
Added: cache.put(userId, profile);
Added: return profile;
}
@Transactional
public Profile updateProfile(long userId, ProfileUpdate update) {
Removed: Profile profile = getProfile(userId);
Added: Profile profile = repository.findById(userId)
Added: .orElseThrow(() -> new ProfileNotFoundException(userId));
profile.setDisplayName(update.displayName());
profile.setBio(update.bio());
return repository.save(profile);
}
}