mars102009
Parcourir de gros volume de données en 2 lignes de code ?
Lorsque nous ne pouvons rien
supposer du volume ou du nombre de résultat qu'une requête va nous
retourner (hormis le seul fait que la mémoire vive ne sera pas du tout
suffisante...), nous avons deux principales techniques pour faire en
sorte que tout ce passe bien :
- utiliser un chargement à la demande des différents objets, ce qui nécessite d'avoir une session ouverte pour toute la durée de traitement,
- utiliser un mécanisme de pagination en suivant le pattern DAO sans garder de session.
C'est cette dernière technique que je vais utiliser ici. Cependant, un mécanisme de pagination classique a plusieurs inconvénients majeurs car:
- il faut gérer la notion de page courante,
- la navigation au sein des données à de gros impacts sur le code: il est tout de suite moins clair, moins évolutif, etc...
La théorie par la pratique
Imaginez:- un simple bean "CarBean" qui possède deux attributs "color" et "name",
- une DAO "CarBeanDao" qui permet les opérations classiques d'enregistrement/suppression et deux méthodes "list" pour parcourir l'ensemble des voitures, et "find"pour lister uniquement celle qui possède un attribut spécifique.
- une base de données possédant des milliers de milliers d'entité "CarBean"
Pour accéder à 10 ou 1000000 entités "CarBean", le code client sera toujours semblable à cela:
public void testCarBean() {
initializeData();
System.err.println("***************************************************");
System.err.println("Find all car ");
System.err.println("***************************************************");
for(CarBean car: m_carBeanDao.list())
System.err.println(car.getName());
System.err.println("***************************************************");
System.err.println("Find all car with a specified color");
System.err.println("***************************************************");
for(CarBean car: m_carBeanDao.find("blue"))
System.err.println(car.getName());
}
private void initializeData() {
for (int i = 0; i <= 22; i++)
m_carBeanDao.save(new CarBean("car " + i, "blue"));
for (int i = 0; i <= 23; i++)
m_carBeanDao.save(new CarBean("car " + i, "red"));
}
Personnellement, je n'ai pas encore trouvé plus simple qu'un "
foreach
"...
Tout le mécanisme est réalisé au niveau de la classe "CarBeanDao" en utilisant deux objets "ValueIterator" et "ValueHandler" dont voici un diagramme de classe:
"ValueHandler" est une interface qui définie une méthode qui va interroger la base de donnée à la demande.
"ValueIterator" est une sorte d'itérateur qui va gérer pour vous toute la problématique liée à la pagination, dont voici les deux principales méthodes:
L'implémentation au niveau de la DAO consiste à écrire un code java équivalent à ceci:
Vous vous occupez uniquement de créer votre requête de façon normale, sans les soucis de pagination...
Pour les curieux, voici un diagramme de séquence qui explicite de façon plus détaillée ce qui se passe lors de l'appel à la méthode "find" :
Le projet
Je vous ai rassemblé toutes les sources nécessaires (les classesValuesXXXX
, les classes d'exemple et le test unitaire) dans un projet eclipse.
Ce projet est organisé comme suit:
Pour le tester vous devez mettre à jour le fichier "utility.properties" qui contient la chaîne de connexion à la base de données, et la classe path de façon à référencer les projets Spring, hibernate...
Si vous rencontrez des problèmes, ou avez des suggestions n'hésitez pas :-)
un commentaire Fil des commentaires de ce billet
Le lundi 28 février 2011, 15:35
Bonjour,
Vous pouvez retrouver le code source associé à cet article sur https://code.google.com/p/blog-intelligents-ia/.
J'en ai profiter pour maveniser ce petit jar, et je souhaite très bientôt mettre à jour cet exemple notamment au sujet de la gestion des DAO, en utilisant JPA.
La classe de test utilise h2 comme base de données locale, pour faire tourner l'exemple vous avez juste a lancer les test unitaire avec votre ide favorie, ou:
Bonne lecture