Ce n'est pas un scoop même si cela mérite souvent d'être rappelé, la base de données est un élément crucial pour à peu prés toute application professionnelle. Cruciale car c'est elle qui héberge le système d’information et qui, à ce titre, a beaucoup plus de valeur que tous les applicatifs, aussi complexes soient-ils, qui gravitent autour. Cruciale aussi en terme de performance car une base mal choisie, mal paramétrée ou mal utilisée, détruira systématiquement les plus louables efforts d'optimisation. Un point à garder en tête lorsqu'en Java (ou ailleurs) arrivent le moment d'écrire ou de lire dans une base et que se pose la Grande Question : persistance ou pas persistance...
Pour faire simple, une base de données est assez régulièrement... relationnelle. Que ce soit Oracle, Sybase, Postgresql ou MySQL, toutes fonctionnent avec des tables, des colonnes, des valeurs et des relations.
Le problème est que le développeur, lui, pense "Objet". Il aime les classes, les instances, les collections et les booooooo diagrammes
UML
.
Et lorsque Dédé (notre développeur) a fini d’implémenter son architecture à l’aide de son langage de haut niveau qu'il aime tant, il se retrouve généralement face à un mur : "Comment diantre faire manger mes beaux objets tous hérités les uns des autres à cette vilaine base de données archaïque qui ne connaît que des tables toutes plates ?"
Dédé prend alors une grande inspiration. Retroussant ses manches les bras levés tel un pianiste, il commence à se coltiner une par une les méthodes méthodes qui vont traduire les beaux objets en ce langage d'un autre temps, le SQL.
Mais au bout du 10ième objet traduit, Dédé fatigue, son esprit vagabonde et il se dit : «Ce serait tout de même plus simple si j’écrivais une fonction qui traduise automatiquement mes objets en SQL !! ».
Très content de son idée, et surtout d’arrêter de traduire comme une brute, il fabrique assez vite sa fonction magique. Et ça marche tréééés bien ! Il se dit alors « continuons, INSERT, UPDATE, c’est pareil, je vais unifier tout cela ».
Et sur cette bonne énergie, au bout d’une semaine, Dédé dispose d’une très fonctionnelle usine à gaz toute automatique. Tu lui colles les objets d’un côté et elle te crache le SQL de l’autre. Et vice-versa.
Dédé sans le savoir vient ainsi de créer la première « couche de persistance », le google-translate de la base de donnée. Et il est ra-vis ! Il a dépensé un peu plus que le temps prévu à l’origine mais le résultat est superbe. Il valide donc son code et fait sa livraison.
Mais quelques jours plus tard, débarque dans le bureau son directeur de projet. Il est fumasse, une armée de Nazguls-utilisateurs-testeurs lui est tombée sur le paletot en se plaignant que l’application mettait prés de 10 minutes à réagir à chaque sollicitation. Dédé ne voit pas où est le problème, « ça marche nickel sur ma machine », dit-il quelque peu vexé. « C’est sûrement un problème de Oracle|Cluster|CPU|Mémoire|Machine à café ». Ce à quoi le directeur de projet lui répond, avec patience... « Oui, c’est possible... Ou alors tu n’as que trois données de test qui se battent en duel sur ta bécane, c’est possible ça aussi non ? ».
Dédé a bien sûr tenté d’optimiser « à donf » son code, en le multi-threadant dans tous les coins faisant tomber le temps de réponse à... 9 minutes. Peu pas faire mieux, il est à fond là Dédé... et l’histoire s’arrête là, et le projet aussi. Il a été boudé par les Nazguls qui préfèrent encore utiliser leur feuille Excel et l’usine a Gaz de Dédé a terminé sa courte vie sur un obscure disque de backup.
Mais l’idée de la couche de persistance elle, n’est pas morte, bien au contraire. Elle a germé, fait des petits, jusqu’à aboutir à une énorme usine à Gaz, tout en chrome plus connue sous le nom d'« Hibernate ».
Mais il y a une différence cependant. Avec Hibernate, que ce soit sur le papier, dans les spécifications, sur le site, dans les forums, tout le monde s'accorde à dire : "ça marche nickel, même que Hibernate il te produit des requêtes plus optimisése que ce que tu aurais fait à la main". En somme, Hibernate serait plus rapide que JDBC. Et bien on va voir ça....
Je suis parti sur l’exemple fournit dans le tutoriel d’Hibernate. Dans cet exemple nous avons une très simple table Event et l’objet qui lui est associé avec seulement trois champs. Pas de relation, pas d’exotisme. J’ai juste rajouté une méthode pour sauvegarder un objet modifié et encadré les fonctions histoire de répéter 1000 fois l’opération. La session Hibernate est créée à l'extérieur de la boucle et n’est pas prise en compte dans le calcul du temps passé :
J’ai choisi délibérément de faire une transaction par itération car c’est ainsi que cela se passe dans la vraie vie. Je ferais la même chose avec JDBC en faisant un commit à chaque tour.
Je prends tout ce luxe de précaution d’introduction pour éviter toute envolée lyriquo-trollesque. En gros, si vous pensez que ce code n’est pas optimisé, il faut aller engueuler les gens qui ont écrit le tutorial. Moi je n’y suis pour rien, j’ai fais juste comme on m’a dit de faire.
Pour la version "à la main", je travaille sur la même base qu'hibernate, avec le mêmes pilote JDBC. L’équivalent de la méthode donnée plus haut est donc :
Alors oui, le code JDBC est bien moins joli que le code Hibernate, mais voyons ce que cela donne côté performances.






Bon, j'ai comme l'impression que tout cela se passe de commentaire ou presque : Hibernate est littéralement écrasé.
Bon, c'est pas un scoop non plus, mais cela a le mérite de tordre un peu le coup à la légende urbaine laissant croire jusqu'à un gain de performance avec Hibernate. Je veux bien accepter l'idée que dans des cas plus complexes de tables liées les unes aux autres Hibernate puisse obtenir des performances comparativement moins désastreuses mais pour des choses simples, le résultat est là.
Une couche de persistance, quelle qu'elle soit, a un coût. Et plus la volumétrie augmente, plus ce coup devient prépondérant. Un coût qui ne s'évalue pas seulement comme le pense certains à la qualité et au nombre des requêtes émises, mais aussi aux ressources utilisées pour les fabriquer, et c'est bien là que le bas blesse.
Maintenant utiliser ou pas Hibernate ou équivalent (comme le système des EJB 2.0) est une question de choix d'architecture et de besoin. L'idée n'est pas ici de jeter le bébé avec l'eau du bain mais bien de prendre conscience que chaque "facilité" a une contrepartie et que dans certains cas cette dernière peut être létale à un projet.