Problématiques de cohérence des données
Lors de l'utilisation combinée de Spring Boot et Redis, maintenir la synchronisation entre les données du cache et celles de la base de données représente un défi majeur. Les incohérences surviennent fréquemment dans des environnements hautement concurrentiels lorsque les mises à jour du cache et de la base ne sont pas atomiques.
Origines des incohérences
- Stratégie de mise à jour inadéquate : Séquence incorrecte des opérations entre cache et base de données
- Accès concurrentiels : Modifications parallèles non synchronisées
- Latence réseau : Délais différentiels lors des écritures
Stratégies de résolution
Politique de mise à jour du cache
Privilégier l'approche "base de données d'abord" : modifier la base avant le cache pour garantir la source de vérité.
@Service
public class ClientService {
@Autowired
private ClientRepository repository;
@Cacheable(value = "clients", key = "#identifiant")
public Client obtenirClient(Long identifiant) {
return repository.trouverParId(identifiant).orElse(null);
}
@CachePut(value = "clients", key = "#client.id")
public Client modifierClient(Client client) {
return repository.sauvegarder(client);
}
}
Invalidation du cache
Suppprimer les entrées du cache lors des modifications pour forcer un rechargement ultérieur.
@CacheEvict(value = "clients", key = "#identifiant")
public void supprimerClient(Long identifiant) {
repository.effacerParId(identifiant);
}
Cohérence par écriture atomique
Utiliser les transactions pour lier les mises à jour de la base et du cache.
@Transactional
public Client mettreAJourClient(Client client) {
Client clientModifie = repository.sauvegarder(client);
redisTemplate.opsForValue().set("client::" + client.getId(), clientModifie);
return clientModifie;
}
Mise à jour asynchrone
Découpler les mises à jour du cache pour améliorer la réactivité.
@Async
public void rafraichirCache(Client client) {
redisTemplate.opsForValue().set("client::" + client.getId(), client);
}
Séparation lecture/écriture
Distinguer les flux de lecture (cache) et d'écriture (base de données).
@Cacheable(value = "clients", key = "#identifiant")
public Client lireClient(Long identifiant) {
return repository.trouverParId(identifiant).orElse(null);
}
@Transactional
public Client ecrireClient(Client client) {
Client resultat = repository.sauvegarder(client);
redisTemplate.opsForValue().set("client::" + client.getId(), resultat);
return resultat;
}