I. Introduction▲
Aujourd'hui, je me suis connecté à mon compte GMail, passé quelques appels professionnels, ajouté quelques sources dans Subversion, installé quelques RMP sur ma distribution Linux… Mais pourquoi est-ce que je vous parle de ça ? Eh bien tout simplement car GMail, SVN, RPM ont un élément en commun, ils stockent certaines de leurs données dans une base Berkeley DB.
II. À propos de Berkeley DB▲
Berkeley DB (que nous nommerons BDB) fait partie de la famille des bases de données « clé-valeur » et est sans doute le produit de cette famille le plus utilisé au monde avec plusieurs dizaines de millions de déploiements revendiqués par l'éditeur. La première version de BDB remonte à 1986 et est la propriété d'Oracle depuis février 2006.
III. La famille de Berkeley DB▲
III-A. Oracle BDB Core▲
Cette version de Berkeley DB est écrite en C ANSI et peut être utilisée comme une bibliothèque pour accéder aux données persistées. Oracle BDB fournit de nombreuses interfaces pour différents langages de programmation (C, Perl, PHP, Python…).
III-B. Oracle BDB XML Edition▲
Cette version est une surcouche de BDB. Cette version XML permet de stocker et récupérer facilement des documents XML. L'utilisation de XQuery permet d'accéder aux documents XML stockés.
III-C. BDB Java Edition▲
Cette version de Berkeley DB, 100 % Java est une base embarquée adoptant le format de stockage clé-valeur. De plus, BDB JE est très performante et flexible. Cette base supporte les transactions, permet de stocker des objets Java en utilisant seulement quelques annotations.
IV. Les fonctionnalités-clés▲
Chaque membre de la famille BDB possède différentes fonctionnalités. Dans toutes les familles de BDB, nous pouvons remarquer les fonctionnalités suivantes.
Feature Set | Description |
---|---|
Data Store (DS) | 1 Writer and n reader |
Concurrent Data Store (CDS) | n writers and n snapshot reader |
Transactional Data Store (TD) | Full ACID support on top of CDS |
High Availability (HA) | Replication for fault tolerence. Fail over recovery support |
Le tableau suivant décrit les différences entre BDB "core" et BDB JE.
DS | CDS | TS | HA | |
---|---|---|---|---|
BDB/BDB XML | X | X | X | X |
BDD JE | X | X |
V. Les fonctionnalités additionnelles▲
Vous trouverez les fonctionnalités qui rendent BDB unique !
Fonctionnalité | Bénéfice |
---|---|
Locking | Haute concurrence |
Données stockées dans le format natif de l'application | Performance et pas de conversion nécessaire |
API et pas de SQL | Performances et flexibilité et contrôle |
In Process et pas de client/serveur | Performances et pas d'IPC nécessaire |
Zéro administration | Coût de possession faible |
Transactions ACID et récupération | Fiabilité et données intègres |
Dual licences | Open/Close source distributions |
En mémoire ou sur disque | Transacted caching/Persisted data store |
Similar data access API | Facilité de passer de BDB à BDB JE |
Faible dépendance vers des bibliothèques tierces | Facile à déployer et à utiliser |
Bases de données de grandes capacités | Virtuellement pas de limite de base de données |
Et pour ce qui est BDB Java Edition, vous trouverez ses propres fonctionnalités dans le tableau ci-dessous :
Fonctionnalité | Bénéfice |
---|---|
Fast, Indexed, B-Tree | Récupération des données très rapide |
Java JEE JTA et JCA Support | Intégration avec les serveurs d'applications Java EE |
Efficient Direct Persistence Layer | Utilisation d'annotations pour stocker les graphes d'objets Java |
Easy Java Collections API | Manipulation transactionnelle des API de base au travers de Collections Java améliorées |
Low Level Base API | Travailler avec des schémas de données dynamiques |
JMX Support | Possibilité de monitoring |
VI. Introduction à Berkeley DB Java Edition▲
VI-A. Installation▲
Tout d'abord, débutons par le commencement. Pour pouvoir utiliser BDB Java Edition, vous devez l'installer à l'adresse suivante : http://www.oracle.com/technetwork/products/berkeleydb/downloads/index.html.
L'installation de Berkeley DB est assez simple, il suffit de décompresser l'archive que vous venez de télécharger !
Le seul fichier dont vous aurez besoin pour faire fonctionner les exemples que nous verrons plus tard est le : "je-*.jar".
VI-B. Les API d'accès aux données▲
BDB JE fournit trois API pour accéder aux données :
- l'API de base fournit un simple modèle clé-valeur pour stocker et récupérer les données ;
- l'API DPL (Direct Persistence Layer) qui vous laisse persister n'importe quelle classe Java comportant un constructeur par défaut en base de données. Cette API vous permet de récupérer les données avec des fonctionnalités de recherche assez riches ;
- la Collection API qui étend la Java Collection API avec le support de la persistance et des transactions en plus de l'accès aux données.
VI-C. L'API de base par la pratique▲
// Ouverture de la base de données et création si nécessaire
EnvironmentConfig environmentConfig =
new
EnvironmentConfig
(
);
environmentConfig.setAllowCreate
(
true
);
// Physiquement où se trouve la base
Environment environment =
new
Environment
(
new
File
(
System.getProperty
(
"java.io.tmpdir"
)), environmentConfig);
DatabaseConfig databaseConfig =
new
DatabaseConfig
(
);
databaseConfig.setAllowCreate
(
true
);
databaseConfig.setSortedDuplicates
(
false
);
Database database =
environment.openDatabase
(
null
, "BDBJESample"
, databaseConfig);
// Enregistrement en base
DatabaseEntry key =
new
DatabaseEntry
(
"keyValue"
.getBytes
(
"UTF-8));
DatabaseEntry data =
new
DatabaseEntry
(
"dataVAlue"
.getBytes
(
"UTF-8));
database.put
(
null
, key, data);
// Récupération des enregistrements
DatabaseEntry searchEntry =
new
DatabaseEntry
(
);
database.get
(
null
, key, searchEntry, LockMode.DEFAULT);
String found =
new
String
(
searchEntry.getData
(
),"UTF-8"
);
// Mise à jour de l'enregistrement
database.put
(
null
, key, data);
// Suppression en base
database.delete
(
null
, key);
// Fermeture de la connexion à la base
database.close
(
);
environment.close
(
);
Comme vous pouvez le remarquer, l'utilisation de cette API est très simple mais assez verbeuse.
VI-D. L'API DPL par la pratique▲
Tout d'abord, avant de commencer à vous parler de DPL, même si nous sommes dans l'univers « NoSQL », il est toujours possible de faire une analogie avec le SQL.
Terme SQL | Équivalence Oracle DPL |
---|---|
Database | Environment |
Table | Primary Index and its related secondary indices |
Primary Index | Primary Index |
Secondary Index | Secondary Index |
Tuple/Row | Entity |
L'exemple que je vais vous présenter se décompose en deux parties. Premièrement, un entity bean et une classe de management qui gère le CRUD (Create-Replace-Update-Delete) au-dessus de l'entity bean.
@Entity
public
class
Employee {
@PrimaryKey
public
Integer id;
public
String name;
public
String forname;
@SecondaryKey
(
relate =
Relationship.MANY_TO_MANY,
relatedEntity =
Project.class
,
onRelatedEntityDelete =
DeleteAction.NULLIFY)
public
Set<
Long>
projects;
public
Employee
(
Integer id, String name, String forname, Set<
Long>
projects) {
this
.id =
id;
this
.name =
name;
this
.forname =
forname;
this
.projects =
projects;
}
}
Il s'agit en effet d'un simple POJO avec quelques annotations. Ceux qui connaissent un peu JPA ne seront pas perdus !
Le code ci-dessous vous montre comment accéder aux données présentes dans le POJO Employee.
@Entity
EnvironmentConfig environmentConfig =
new
EnvironmentConfig
(
);
environmentConfig.setAllowCreate
(
true
);
// Physiquement où se trouve la base
Environment environment =
new
Environment
(
new
File
(
System.getProperty
(
"java.io.tmpdir"
)), environmentConfig);
StoreConfig storeConfig =
new
StoreConfig
(
);
storeConfig.setAllowCreate
(
true
);
EntityStore entityStore =
new
EntityStore
(
environment, "BDBJEDPLSample"
, storeConfig);
PrimaryIndex<
Integer, Employee>
employeePrimaryIndex =
entityStore.getPrimaryIndex
(
Integer.class
, Employee.class
);
employeePrimaryIndex.putNoReturn
(
new
Employee
(
12
,"francois"
, "ostyn"
, null
));
Employee employee =
employeePrimaryIndex.get
(
12
);
Assert.assertNotNull
(
employee);
employeePrimaryIndex.delete
(
12
);
employee =
employeePrimaryIndex.get
(
12
);
Assert.assertNull
(
employee);
entityStore.close
(
);
environment.close
(
);
Dans l'exemple ci-dessus nous ne gérons ni les transactions, ni des relations complexes.
VII. Description de l'environnement de Berkeley DB Java Edition▲
Une base de données BDB JE est composée d'un ou plusieurs fichiers de logs qui sont situés dans le répertoire d'environnement.
Par défaut, leur taille est de 10 Mb et peut être modifiée (par exemple, augmenter la taille des logs permet de limiter le nombre d'I/O).
VIII. Le support des transactions▲
Pour gérer les transactions avec DPL, il faut faire quelques modifications dans son code.
EnvironmentConfig environmentConfig =
new
EnvironmentConfig
(
);
environmentConfig.setAllowCreate
(
true
);
environmentConfig.setTransactional
(
true
); // << gestion des transactions
TransactionConfig transactionConfig =
new
TransactionConfig
(
); // << gestion des transactions
transactionConfig.setReadCommitted
(
true
); // << gestion des transactions
// Physiquement où se trouve la base
Environment environment =
new
Environment
(
file, environmentConfig);
StoreConfig storeConfig =
new
StoreConfig
(
);
storeConfig.setAllowCreate
(
true
);
storeConfig.setTransactional
(
true
); // << gestion des transactions
Transaction tx =
environment.getThreadTransaction
(
); // << gestion des transactions
environment.beginTransaction
(
tx, transactionConfig); // << gestion des transactions
EntityStore entityStore =
new
EntityStore
(
environment, "BDBJEDPLSample"
, storeConfig);
PrimaryIndex<
Integer, Employee>
employeePrimaryIndex =
entityStore.getPrimaryIndex
(
Integer.class
, Employee.class
);
employeePrimaryIndex.putNoReturn
(
new
Employee
(
12
, "francois"
, "ostyn"
, null
));
tx.commit
(
);
Bien entendu, vous pouvez préciser un timeout transactionnel, ainsi que le retry policy…
IX. Monitorer une application utilisant BDB JE▲
Étant donné que BDB JE est totalement écrit en Java, ce dernier expose bon nombre de métriques via JMX. Pour l'activer, il faut positionner la property "-DJEMonitor=true" au démarrage de la JVM.
Ceci peut être très utile pour modifier le comportement de votre application à chaud ou récupérer certaines métriques.
X. Les sources▲
Vous pourrez trouver les sources présentées dans les exemples sur GitHub à l'adresse suivante : https://github.com/francoisostyn/bdbJeSampleFost.
XI. Conclusion▲
À l'heure où l'on nous parle de bon nombre de solutions « NoSQL », Berkeley DB Java Edition est bien souvent oublié et à tort. En effet, cette version est d'une performance redoutable. Cependant, je regrette tout de même la « double licence » qui pourra freiner beaucoup de monde.
En tout cas, BDB JE est parmi mes solutions NoSQL clé-valeur !
XII. Remerciements▲
Cet article a été publié avec l'aimable autorisation de la société SoatSoat.
Nous tenons à remercier ClaudeLELOUP pour sa relecture orthographique attentive de cet article et Mickael Baron pour la mise au gabarit.