Utiliser les fonctions, triggers et procédures stockées MySQL présentent de nombreux avantages, mais aussi quelques difficultés. Nous allons détailler ces différents points, et voir comment contourner les quelques éléments qui pourraient poser problème (versionning, tests unitaires…).

procédures stockées MySQL stored procedures

Avantages à l’utilisation des fonctions, triggers et procédures stockées MySQL

Si vous êtes dans le cadre d’une application web en mode LAMP, avec du code PHP et une base de données MySQL, deux choix s’offrent à vous au moment d’implémenter vos règles métier. Soit créer des méthodes PHP dans vos classes, ou utiliser des fonctions ou procédures en MySQL. La question du choix à faire peut légitimement se poser, chacune des méthodes ayant ses avantages et inconvénients.

Développer côté base de données présentent plusieurs avantages :

  • Si vous êtes comme moi dans un environnement mixte (serveurs LAMP et serveurs Microsoft avec notamment SQL Server et SSIS), vous ne pourrez pas utiliser dans SSIS par exemple les développements que vous avez fait en PHP. Alors que vous pourrez exécuter et récupérer sans problème le jeu de données que vous renverra votre procédure stockée. Cela vous évitera donc de devoir coder deux fois la même chose, en plus dans deux environnements différents (avec tous les problèmes que cela peut vous apporter).
  • Cela vous apporte un plus en terme de sécurité, car vos données ne sont plus modifiées en direct par un code externe. Elles passent par votre couche de développement SQL, où vous pouvez définir vos différents contrôles. Le trigger dans le cadre de la sécurité de vos données est également primordial, car c’est le seul qui vous permet des contrôles qui ne pourront jamais être outrepassés.
  • Les règles métiers sont au plus proche de la donnée. Cela évite donc pour vos traitements de traverser à chaque fois toutes les couches (navigateur côté client, serveur web, interpréteur PHP et base de données). Vous êtes déjà au niveau le plus bas.

Vous êtes donc proche de la donnée, vos développements font foi pour garantir l’intégrité de vos données, et ils sont également réutilisables sur différentes applications et sur différents environnements. Que demande le peuple.

Inconvénients et solutions de contournement

Vous venez de voir que les avantages étaient nombreux et non négligeables. En revanche, cela ne va pas sans poser certains soucis. Mais une fois ces problématiques intégrées, il devient assez simple de proposer des solutions pour y faire face.

Versionning du code

C’est un souci souvent cité lors de développement côté MySQL. Le code de vos fonctions, triggers et procédures stockées MySQL n’est pas versionnable, et une fois chargé sur votre serveur web vous avez l’impression de « perdre la main » sur votre code.
Autre problème, si vous voulez faire une recherche complète dans votre application avec votre IDE préféré (par exemple dans le cadre d’une refactorisation de code impliquant un changement de nom dans un champ), il ne verra pas le code MySQL.

La solution à ce problème est assez simple : il faut intégrer votre code SQL à votre application, et mettre en place un mécanisme pour charger votre code sur votre base de données.

Voyons cela plus en détail. Si vous avez une fonction, un trigger ou une procédure stockées MySQL à créer, vous allez créer le code dans votre IDE. L’idéal est sans doute de dédier un dossier de votre application (nommons le SQL), avec des sous-niveaux permettant de les classer par type (fonction, trigger, vue, procédure) et avec une arborescence correspondant à votre application. Les fichiers créés seront d’extension .sql (vous bénéficierez en plus de la coloration syntaxique, voire des corrections de votre IDE qui sait en général reconnaître le langage SQL).

Vous procéderez ainsi pour tout votre code SQL, vous ajouterez au fur et à mesure votre code, en ajoutant le DROP et le CREATE. Il vous faudra définir également un DELIMITER particulier ($$ par exemple, ou tout autre que vous serez certain de ne pas rencontrer dans votre code SQL) que vous ajouterez après l’instruction DROP et à la toute fin de votre trigger, fonction ou procédure stockée MySQL.

Comme il s’agit de fichier, vous pourrez tout à fait les gérer dans votre outil de gestion de version du code, par exemple avec Git et SourceTree :

Version fichiers SQL avec Git et SourceTree

Reste maintenant à charger ce code sur votre base.

Pour cela il vous suffit de mettre en place un script qui récupérer vos fichiers .sql (par exemple avec un RecursiveDirectoryIterator), les agrège dans un fichier temporaire (via un file_put_contents par exemple) et joue ensuite ce fichier sur votre base (par l’appel de mysql en ligne de commande). Vous pouvez également mettre un template de header pour le fichier temporaire, avec notamment l’instruction DELIMITER pour fixer le délimiteur que vous aurez choisi.
Si vous voulez aller un peu plus loin, vous pouvez ajouter des arguments à votre script, pour par exemple ne traiter que les fonctions, ou les procédures, ou les triggers. Ou bien encore pour ne sortir qu’un fichier sql d’agrégation sans le lancer sur la base (pour contrôle).
Si vous réalisez vos passages en production via un dépôt de version, rien n’empêche également de mettre en place un script de mise en production qui irait mettre à jour la production avec le dépôt de votre projet, et qui jouerait ensuite la mise en place de vos fichiers sql.

Tests unitaires

Un autre reproche possible au fait d’utiliser des triggers, fonctions et procédures stockées MySQL est l’impossibilité de les intégrer dans des systèmes de tests unitaires automatisés qui peuvent être faits par exemple avec Jenkins dans un process d’intégration continue.

C’est vrai. En revanche si vous développez une fonction MySQL par exemple, il y a de fortes chances pour qu’elle soit utilisée ensuite dans un méthode PHP qui se chargera de l’appeler en lui passant des paramètres.
Hors, cette méthode PHP peut tout à fait être appelée elle dans un test unitaire.
Prenons l’exemple d’une procédure stockée qui met à jour les tarifs d’un article. Vous l’avez développé en MySQL car elle peut être appelée par différents outils, et vous vouliez être sûr d’avoir un point de passage unique pour la modification de prix. Cette procédure peut être appelé par la méthode majPrix de votre classe article PHP, que vous pourrez tester unitairement.

Enfin, si l’on parle de tests unitaires (hors intégration continue là), il n’y a rien de plus simple que de tester une procédure stockée MySQL. Il suffit de l’appeler en ligne de commande en lui passant les bons paramètres. C’est même encore moins contraignant que de tester une méthode PHP. Rien n’empêche même de développer un script SQL permettant de tester avec différents paramètres l’appel d’une fonction ou d’une procédure stockée MySQL.

Conclusion

Je vous livre ici mon point de vue, n’hésitez pas en commentaires à me faire part du votre, de vos retours d’expérience ou d’autres contraintes qui ne seraient pas listées ci-dessus.