Stored procedures

Stored procedures

Nous pouvons pré-coder des fonctions directement dans la base de données, qui se compose de plusieurs commandes SQL, ainsi que des transactions.

Quels avantages ?

  • La logique business est codĂ©e Ă  un point central de la plateforme

  • Moins d’erreurs

  • Maintenance plus facile

  • EmpĂȘcher de l’accĂšs direct aux tables par les utilisateurs et/ou APIS

  • Abstraire de la complexitĂ©

  • ContrĂŽle d’accĂšs et permissions

Imaginons le transfert d’argent dans une plateforme bancaire. La sĂ©quence de requĂȘtes se trouve oĂč ?

On peut, bien sûr, implémenter la logique dans le client :

Logique business : coté client

En revanche, ceci est une trÚs mauvaise idée :

  • Duplication X fois de la logique (pour chaque type de client qui existe) Si le rĂšglement bancaire change ?

  • Il ne faut jamais faire confiance aux clients !

Logiquement, la plupart de la logique se trouvent plutĂŽt en interne, dans nos APIs :

Logique business : coté API

C'est plus sĂ©curisĂ©, mais, on a potentiellement les mĂȘmes problĂšmes de maintenance. Il y a une duplication de la logique sur les diffĂ©rents APIs. Une solution potentielle est d'avoir un API monolithique, ou bien une librairie partagĂ©e entre toutes les implĂ©mentations.

Sinon, on peut héberger le logique business juste à cÎté des données :

Logique business : coté SGBDR

Malgré l'API utilisé, la séquence nécessaire pour une opération reste inchangé. Et en plus, ni l'API ni le client voit les détails de l'opération.

Nous allons créer une procédure stockée qui agit sur plusieurs tables pour affecter un transfert d'argent. Voici le DDL pour les deux tables :

On peut rĂ©diger une fonction (en tant que stored procedure) qui peut ĂȘtre invoquĂ© Ă  tout moment, avec des paramĂštres, pour effectuer un transfert d'argent :

Un délimiteur temporaire

On commence notre procédure stockée par :

En fait, ici, on change le symbole reconnu par l'interprĂšte SQL pour signaler la fin d'une commande. On le fait parce qu'on veut empĂȘcher l'interprĂšte d'interprĂ©ter les commandes qui se trouvent Ă  l'intĂ©rieur de notre procĂ©dure qu'on est en train de rĂ©diger !

Pour signaler la fin de déclaration de notre procédure, on évoque le délimiteur :

Une fois terminé, on rétablit le délimiteur :

Commande pour la création d'une procédure

La procédure se crée avec une syntaxe précis :

AprÚs la déclaration d'une procédure, on peut l'invoquer à tout moment avec :

Gestion d'erreurs

Il faut toujours penser aux erreurs qui peuvent arriver. Nous commençons donc par préciser que faire en cas d'erreur :

Dans cet exemple, on précise que dans le cas d'un sqlexception, on fait d'abord un rollback, puis on renvoie l'erreur plus haut dans le tas d'appels (avec resignal).

Comment signaler manuellement une erreur ? Avec la commande signal :

Le state 45000 est réservé aux erreurs personnalisées.

Invoquer une procédure stockée

Nous commençons avec les données suivantes :

customer_id
name
surname
balance

1

Kevin

Glass

5000.00

2

Pierre

Laurendeau

7000.00

3

Florence

Perrousset

3500.00

On peut utiliser notre procĂ©dure afin d'effectuer un transfert de 2000 € de Kevin Ă  Pierre :

customer_id
name
surname
balance

1

Kevin

Glass

3000.00

2

Pierre

Laurendeau

9000.00

3

Florence

Perrousset

3500.00

Tout s'est bien passé !

Essayons avec une erreur :

Lister, modifier une procédure

On peut récupérer la liste de procédures pour notre base de données (on filtre par base de données, car il y en a déjà d'autres qui existent dans le SGBDR) :

On peut récupérer le listing d'une procédure existante :

On ne peut pas modifier directement les procédures. On est obligé de les supprimer et les remplacer avec une autre version.

Certains clients comme MySQL Workbench ont une interface qui facilite ces opérations.

Il est donc assez difficile à récupérer et modifier une procédure stockée. Pour cette raison, certains développeurs ne les aiment pas :

  • Pas trĂšs compatible avec la gestion de code moderne (ex. GIT)

  • Difficile Ă  distinguer les versions dĂ©ployĂ©es

Exercice

Vous ĂȘtes Ă©diteur d’une solution de publicitĂ© en ligne qui va rĂ©compenser l’internaute de l’attention passĂ©e sur les pubs (exemple, le navigateur Brave).

Au cƓur de votre solution est la logique business suivante :

  • Vous avez une base d’éditeurs partenaires (journaux, blogs, mĂ©dia, etc.). Chaque Ă©diteur classe leurs contenus par une ou plusieurs catĂ©gories : sport, actualitĂ©, divertissement, science, politique, enfant

  • Un annonceur de pub prĂ©paye un budget total pour une publicitĂ©. Pour chaque pub, l’annonceur prĂ©cise le prix-par-vu qu’il est prĂȘt Ă  payer par chaque catĂ©gorie cible. Plus le prix est Ă©levĂ©, plus la pub aura la chance d’apparaĂźtre dans un site Ă©diteur de ce genre.

  • Quand la pub apparaĂźt sur le site d’un Ă©diteur de contenu (journal, blog, etc.), le prix (correspondant Ă  la catĂ©gorie) est dĂ©duit du budget total de l’annonceur :

    • 75% est allouĂ© au compte de l’éditeur

    • 25% est allouĂ© au compte de l’internaute

CrĂ©ez le schĂ©ma pour votre solution, ainsi qu’une procĂ©dure SQL qui effectue le transfert de valeur au moment d’une vue sur une page web d’un Ă©diteur.

Votre procĂ©dure doit ĂȘtre tolĂ©rante aux fautes ainsi que des requĂȘtes concurrentes !

Attention : l’annonceur ne peut jamais avoir un solde nĂ©gatif.

Chaque partie prenante doit ĂȘtre capable de rĂ©cupĂ©rer son historique : ex. L’annonceur veut voir la rĂ©partition de dĂ©pense sur les Ă©diteurs, l’éditeur veut voir la rĂ©partition des sources de revenu, l’internaute veut voir l’historique de pubs dĂ©jĂ  vues.

Mis Ă  jour