Introduction

Ce guide explique comment écrire des programmes Python qui utilise la Z Objects Database (ZODB) et le Zope Enterprise Objects (ZEO). La dernière version de ce guide est accessible en anglais à http://www.zope.org/Wikis/ZODB/guide/index.html.

Qu'est ce que la ZODB ?

La ZODB est un système de persistance pour les objets Python. Les langages de programmation persistants offrent la possibilité d'écrire automatiquement les objets vers le disque et de les relire quand ils sont requis par le programme. En installant la ZODB, vous ajoutez cette possibilité à Python.

Il vous est possible de créer votre propre système de persistance des objets Python. Le point de départ habituel d'une telle construction est d'utiliser le module pickle, qui convertit les objets en une représentation texte, ainsi que différents modules de base de données, tels que les modules gdbm ou bsdbd, qui fournissent un moyen d'écrire des chaînes vers le disque et de les relire. Il est très puissant de combiner le module pickle et un module de base de données pour stocker et restituer les objets ; le module shelve qui fait partie de la bibliothèque standard de Python, fait exactement cela.

La difficulté pour le développeur est de gérer explicitement les objets, lire un objet quand il en a besoin et l'écrire sur le disque lorsque l'objet n'est plus requis. La ZODB gère les objets pour vous, les gardes en cache, les écrit sur le disque lorsqu'ils sont modifiés et les supprime du cache s'ils n'ont pas été utilisés depuis un moment.

OODBs vs. DBs relationnelles

La ZODB est une base de données orientée objet (OODB) spécifique à Python. Les bases de données objets commerciales pour le C++ et Java réclament souvent de surmonter certains obstacles tels que l'usage d'un préprocesseur dédié ou que vous n'utilisiez pas certains types. Comme nous allons le voir, la ZODB a aussi quelques pièges à éviter, mais en comparaison la simplicité de la ZODB est à couper le souffle.

Les bases de données relationnelles (RDBs) sont plus communes que les OOBDs. Les bases de données relationnelles stockent les informations dans des tables. Une table consiste en un ensemble de lignes, chaque ligne contient plusieurs colonnes d'informations. (Les lignes sont généralement appelées des relations, et c'est de là que vient le nom de base de données relationnelles).

Mais regardons un cas concret. Notre exemple est issu d'une journée de travail de l'auteur initial à MEMS Exchange, en version simplifiée. Le travail consiste à tracer l'exécution de processus, qui sont constitués d'une liste d'étapes de fabrication dans une usine de semi-conducteurs. L'exécution est réalisée par un utilisateur unique, identifié par un nom et un numéro d'identification. L'exécution est constituée par un nombre déterminé d'opérations, comme déposer quelque chose sur le wafer ou en enlever quelque chose.

Les opérations peuvent avoir des paramètres, qui sont des informations additionnelles requises pour réaliser l'opération. Par exemple, si vous déposez quelque chose sur wafer, vous avez besoins de savoir deux choses : 1) qu'est ce que vous déposez, 2) quelle quantité vous devez déposer. Par exemple vous déposez 100 microns d'oxide de silicium ou 1 micron de cuivre.

Mapper cette structure vers une base de données relationnelles est direct :

CREATE TABLE runs (
  int      run_id,
  varchar  owner,
  varchar  title,
  int      acct_num,
  primary key(run_id)
);

CREATE TABLE operations (
  int      run_id,
  int      step_num,
  varchar  process_id,
  PRIMARY KEY(run_id, step_num),
  FOREIGN KEY(run_id) REFERENCES runs(run_id),
);

CREATE TABLE parameters (
  int      run_id,
  int      step_num,
  varchar  param_name,
  varchar  param_value,
  PRIMARY KEY(run_id, step_num, param_name)
  FOREIGN KEY(run_id, step_num)
     REFERENCES operations(run_id, step_num),
);

En Python, vous pouvez écrire trois classes nommées Run, Operation, and Parameter. Je ne présenterai pas le code de définition des ces classes, car le code est en dehors du propos. Chaque classe devra contenir un constructeur __init__ qui créera les attributs et leur assignera des valeurs par défaut.

Il n'est pas difficile d'écrire du code Python qui instanciera la classe Run et la remplira avec les données venant d'une base de données relationnelle, vous pouvez aussi créer directement un utilitaire pour cette tâche classiquement appelée un mapper objet-relationnel. (Voir http://www.amk.ca/python/unmaintained/ordb.html pour un aperçu rapide d'un test de mapper objet - relationnel en Python, et http://www.python.org/workshops/1997-10/proceedings/shprentz.html pour un autre qui est basé sur la même idée mais qui est utilisé en production).

Néanmoins, il est difficile de réaliser un mapper objet-relationnel rapide; une implémentation simple comme celle réalisée est très lente car elle doit réaliser plusieurs requêtes pour accéder à toutes les données des objets. Plusieurs techniques de cache peuvent optimiser les requêtes SQL et les limiter au strict nécessaire.

Cela aide si vous souhaitez accéder à l'exécution numéro 123. Mais qu'en est il si vous voulez trouver toutes les exécutions dont l'une des étapes possède un paramètre nommé 'thickness' avec une valeur de 2,0 ? Dans une version relationnelle, vous avez deux possibilités peu attrayantes :

  1. Écrire une requête SQL spécialement pour ce cas : SELECT run_id FROM operations WHERE param_name = 'thickness' AND param_value = 2.0

    Si de telles requêtes sont communes, vous pouvez vous retrouver avec énormément de requêtes de ce type. Quand vous modifierez la structure de votre base ou de votre code vous aurez à maintenir toutes vos requêtes.

  2. Utiliser un mapper objet relationnel ne vous aidera pas beaucoup plus. Chercher parmi les exécutions signifie que le mapper déroulera la requête SQL pour lire l'exécution numéro 1 et qu'un code Python vérifiera si l'une de ses étapes possède le paramètre que nous cherchons. Même chose pour l'exécution 2 puis 3 etc. Ce qui aboutit a traitement de nombreuses requêtes SQL, et risque d'être extrêmement long.

Une base de données comme la ZODB va simplement stocker la référence interne entre objets, en conséquence lire un objet unique est plus rapide qu'envoyer une série de requêtes et d'assembler les résultats. Scanner toute les exécutions, est également inefficace.

Qu'est ce que la ZEO ?

La ZODB est fournie avec quelques classes qui implémentent l'interface Storage. Ces classes sont responsables du travail d'écriture des objets Python vers un média de stockage, qui peut être un fichier sur le disque (la classe FileStorage), un fichier BerkleyDB (BDBFullStorage), une base de données relationnelle (DCOracleStorage), ou tout autre média. La ZEO ajoute ClientStorage, un nouveau Storage qui n'écrit pas vers un média physique mais qui envoie chaque requête à travers le réseau vers un serveur. Le serveur qui fait fonctionner une instance de la classe StorageServer, va simplement agir comme le 'front end' d'un média physique de la classe Storage. C'est une idée simple et efficace qui comme on le verra dans la suite du document ouvre énormément de possibilités.

À propos de ce guide

Les premiers auteurs de ce guide travaillaient sur un projet qui utilisait la ZODB et ZEO comme principale technologie de stockage. Ils utilisaient la ZODB pour y stocker les processus, les opérations, un catalogue des processus possibles, des informations utilisateurs, des informations sur les comptes et autres données. Un des objectifs de ce document et de partager notre expérience. Ce guide est un concentré de toute l'expérience acquise lors des nombreuses heures passées à essayer de résoudre un problème. Il a pour but d'éviter à d'autres de passer du temps sur les même erreurs que celles que nous avons faites lors de notre apprentissage.

Les auteurs du projet ZODB sont présentés dans un article accessible ici http://www.amk.ca/python/writing/mx-architecture/

Ce guide et en évolution constante. Si vous souhaitez contribuer et suggérer des éclaircissements ou de nouveau chapitre, envoyez vos commentaires à de@zope.org.

Remerciements

Andrew Kuchling est l'auteur initial de la première version anglaise de ce guide, il a fournit la première documentation de la ZODB pour les programmeur Python. Sa version a été complété de nombreuse fois par Jeremy Hylton et Tim Peters.

Les auteurs remercient les personnes qui ont relevé les inexactitudes et les bogues, qui ont proposé des suggestions sur le texte, ou de nouveau sujet qui ont put être traités : Jeff Bauer, Willem Broekema, Thomas Guettler, Chris McDonough, George Runyan.

Traduction en Français par Michael Launay

Table des matières

Sujet précédent

ZODB - Une Base de données objet native pour python

Sujet suivant

Tutoriel

Cette page


blog comments powered by Disqus