Vous êtes sur la page 1sur 81

db4o

db

Mohamed ELADNANI
Spécificités de db4o
„ Léger
„ Pas de maintenance / administration
„ Simple d’emploi
„ API simple pour Java et .NET
„ Requêtes natives
„ Pas un SGBDOO ODMG, pas de requêtes OQL par
exemple
l
„ Convient bien à une application embarquée (BD pas
partagée
t é entret plusieurs
l i applications)
li ti )
Exemple basique
ObjectContainer bd = Db4o.openFile("bd.data");
Personne personne =
new Personne("Dupond", "Pierre", 35);
// Aj
Ajoute
t dans
d la
l base
b de
d ddonnées
é
bd.store(personne);
bd commit();
bd.commit();
// Passe un exemple de ce qui est cherché
ObjectSet<Personne> personnes =
bd.queryByExample(new Personne(null, null, 40));
for (Personne p : personnes) {
S t
System.out.println(p);
t i tl ( ) }
}
bd close()
bd.cl
Paquetages
„ Tous les paquetages sont des sous paquetages de
com.db4o
„ L paquetage
Le t com.db4o
db4 contient
ti t les
l interfaces
i t f ett
classes de base :
‰ ObjectContainer, ObjectSet,
ObjectContainer ObjectSet
‰ ObjectServer, Db4o (la seule classe)
Connexion à une BD db4o
„ La classe Db4o contient des méthodes static pour
démarrer un moteur db4o
„ 2 façons
f de
d se connecter
t :
‰ en local, à une BD qui se trouve sur la même machine

; une seule connexion en local est permise à un


moment donné
‰ en client-serveur,
client-serveur par une connexion TCP/IP
TCP/IP, sur une
machine distante ; il faut donner un nom d’utilisateur
et un mot de passe
p
Connexion locale

„ La classe Db4o contient des méthodes


static pour démarrer un moteur db4o

„ ObjectContainer openFile(nom) ouvre un


ObjectContainer qui utilisera le fichier nom
comme BD
BD, en mode local
Connexion distante - serveur
„ ObjectServer
Db4o.openServer(fichier, port)
à lancer sur la machine qui contient la BD
„ Lance un serveur qui utilisera le fichier nom comme BD
ett quii attendra
tt d lesl d
demandes
d ded connexion i des
d clients
li t
sur le port indiqué
„ La méthode grantAccess(nom,motDePasse)
grantAccess(nom motDePasse) de la
classe ObjectServer accorde l’autorisation de se
connecter au client de nom et de mot de passe indiqués
Connexion distante - client
„ ObjectContainer
openClient(machine, port, utilisateur, motDePasse)
à lancer sur la machine sur laquelle tourne le client qui
souhaite se connecter distance
„ R
Renvoie i un ObjectContainer
Obj tC t i pour utiliser
tili l BD
la
installée sur la machine distante (sur laquelle tourne un
serveur qui écoute le port indiqué)
ObjectContainer
„ Interface qui représente la connexion à une BD (locale
ou en client-serveur)
„ U objectContainer
Un bj tC t i garde
d un cacheh des
d objets
bj t qu’il
’il
manipule
„ Les informations contenues dans ce cache seront
enregistrées dans la base de données lors d’un commit
de la
a transaction
a sac o
Méthodes de ObjectContainer
j ((1))

„ void store(Object) insère ou modifie un objet dans le


cache du container
„ void
id delete(Object)
d l t (Obj t) pour supprimer
i un objet
bj t dans
d lle
cache du container
„ <T> ObjectSet<T> queryByExample(Object) pour
récupérer des objets qui correspondent au modèle
passé een pa
paramètre
a è e
Persistance par référence
„ Tous les objets référencés par un nouvel objet persistant
sont automatiquement rendus persistant (s’ils ne le sont
pas déjà) par la méthode store (quelle que soit la
profondeur)
„ Attention il n’en
Attention, n en est pas de même pour les objets
passés en paramètre de la méthode store : les objets
référencés et modifiés n’ont pas, par défaut, leurs
modifications enregistrées dans la base au commit (voir
la section sur la configuration de db4o)
Méthodes de ObjectContainer
j ((2))

„ Query query() crée une nouvelle requête SODA (voir


plus loin le langage SODA)
„ <T> ObjectSet<T>
Obj tS t<T> query (surchargée)
( h é ) interroge
i t l BD
la
„ paramètre pour query, choisir dans :
‰ Class<T> : ramène tous les objets de la classe
l
‰ Predicate<T> : critère de sélection ; voir plus loin ; il est
d ajouter un 2ème paramètre pour trier les objets
possible d’ajouter
renvoyés
Méthodes de ObjectContainer (3)

„ close() ferme la connexion


„ commit()
„ rollback()
„ activate(Object,
( j , int p profondeur)) « active » un objet
j
jusqu’à une certaine profondeur (voir section sur les
requêtes)
„ deactivate(Object, int profondeur) met les valeurs d’un
objet à null ou à la valeur par défaut du type primitif,
jusqu’à
jusqu à une certaine profondeur (attention !)
Méthodes de ObjectContainer
j ((4))

„ ext() récupère une interface « avancée »


ExtObjectContainer qui permet d’appeler d’autres
méthodes
éth d sur ObjectContainer
Obj tC t i
„ En fait tous les ObjectContainer de db4o sont des
ExtObjectContainer et on peut donc les caster en ce
type (cf. Graphics et Graphics2D de Swing) et cette
méthode
ét ode é évite
e seu
seulement
e e u un cas
cast
Insertion d’un nouvel objet
j

„ store(objet) ajoute un nouvel objet dans le cache de


l’objectContainer
„ T
Tous l objets
les bj t « nouveaux » référencés
éfé é par l’objet
l’ bj t
seront ajoutés à la base au moment du commit, et ainsi
de suite tant que des objets nouveaux sont trouvés
„ Attention, le parcours récursif s’arrête dès qu’un objet
déjà pprésent
ése dadans
s le
e cac
cache
e es
est rencontré
e co é ; ces obje
objetss ne
e
seront pas mis à jour dans la BD
Validation de la transaction

„ L’ajout d’un nouvel objet dans le cache de


l’objectContainer, comme la mise à jour ou la
suppression ne sera répercutée dans la base de
données que lors de la validation (par la
méthode commit()) de la transaction
Modification d’un objet
j

„ store(objet) enregistre dans le cache les modification


effectuées sur un objet qui est déjà dans le cache
„ L liens
Les li vers lles objets
bj t référencés
éfé é sontt mis
i à jour
j j
„ Les « nouveaux » objets référencés (ceux qui ne sont
pas déjà dans le cache) sont ajoutés au cache
(récursivement)
„ Les objets référencés déjà dans le cache ne sont par
mis à jour dans le cache (voir « profondeur de
modification » dans la suite))
Modification d’un objet
j

„ Attention, l’objet doit avoir été auparavant


récupéré dans la BD (pas de clé primaire
pour savoir si un objet est déjà dans la base)
„ Tout objet créé par Java avec new est
considéré comme un nouvel objet par db4o
Supprimer
pp des objets
j

„ Si l’objet n’est pas déjà géré par


l’objectContainer, il faut tout d’abord le retrouver
depuis la base :
Classe objet =
Bd.queryByExample( ) bd.queryByExample(…);
„ Ensuite il suffit d’appeler
pp la méthode delete sur
l’objet : bd.delete(objet);
Méthode queryByExample
q y y p

„ <T> ObjectSet<T>
queryByExample (Object modele)
throws Db4oIOException,
DatabaseClosedException
„ queryByExample(null) renvoie tous les objets de la
BD
„ queryByExample(modele)
B E l ( d l ) renvoie i tous les
l objets
bj d
de
la BD qui correspondent à l’objet passé en paramètre
(recherche par l’exemple)
l exemple)
Méthode query
„ Méthode surchargée
<T> ObjectSet<T> query(Class<T> classe) récupère
t
tous lles objets
bj t de
d la
l BD dud type
t de
d la
l classe
l passée
é
en paramètre
„ <T> ObjectSet<T>
query(Predicate<T> prédicat) permet une requête
native ; renvoie les objets qui correspondent au prédicat
„ Un deuxième paramètre de type Comparator<T>
permet d’indiquer
d indiquer un ordre dans les objets renvoyés
ObjectSet Item
ObjectSet<Item>

„ Classe fille de List<Item> ; il est recommandé


de le ranger dans une variable de type
List<Item>
„ Attention, l’objectContainer
j sous-jacent
j doit
rester ouvert pendant son utilisation car les
objets de la liste ne sont vraiment récupérés que
lorsqu’on y accède !
Les exceptions

„ La politique de db4o est d’« avaler » les


exceptions quand c’est possible
„ Toutes les exceptions particulières à db4o sont
non contrôlées ((sous-types
y de RuntimeException)
„ Le principal type d’exception est Db4oException
qui enveloppe les exceptions lancées en interne
(elles sont chaînées)
Exceptions
p à l’ouverture de la BD

„ DatabaseClosedException lancé lors d’une opération


de db4o lorsque l’ObjectContainer est fermé alors qu’il
devrait être ouvert
„ DatabaseFileLockedException lancé lors de
ll’ouverture
ouverture du fichier d’une
d une BD (openFile) lorsque le
fichier est bloqué par un autre processus
„ Db4oIOException
b o O cept o lancé a cé lorsque
o sque db
db4o
o a rencontré
e co é u une
e
erreur système pour ses entrées-sorties
Gestion des exceptions
„ Un commit peut lancer plusieurs exceptions
„ Le plus souvent un commit est dans un bloc try-catch
„ Si une exception est levée, il faut envisager d’invalider la
transaction avec rollback()
„ Il estt aussii possible
ibl dde réparer
é lle problème
blè d
dans le
l catch
t h
et de valider ensuite la transaction plus loin dans le
catch
„ Attention, après un rollback les objets Java qui ont été
modifiés pendant la transaction ne reflètent plus les
valeurs de la BD
Exemple
p

try {
// travail avec db4o
...
container.commit();();
}
catch (Exception ex){ .... }
finally {
container close();
container.close();
}
Exemple avec rollback
try {
// travail avec db4o
...
container.commit();
}
catch (Exception ex){
container.rollback();
...
}
finally { container.close(); }
Méthodes de ExtObjectContainer
j

„ boolean isClosed()
„ boolean isStored(Object)
„ void refresh(Object, int profondeur) ramène les
valeurs qui sont actuellement dans la BD jusqu’à une
BD jusqu
BD, jusqu’à
à certaine profondeur
„ void store(Object, profondeur) pour ajouter ou
modifier un objet dans le cache de l’objectContainer
l objectContainer en
indiquant la profondeur de modification
Méthodes de ExtObjectContainer
j

„ <T> T peekPersisted(T objet, int profondeur,


boolean committed) retourne une copie d’un
objet de la BD, avec les valeurs qu’il a
actuellement dans la BD
„ L’objet peut tenir compte ou non des valeurs
modifiées par la transaction en cours avec la
méthode store mais non validées par un commit
(3ème paramètre à false s’il faut en tenir
compte)
Méthodes de ExtObjectContainer
j

„ Identité interne
‰ long getId(objet) retourne l’identité «
interne » (physique)
d’ objet
d’un bj t géré
é é par l’ObjectContainer
l’Obj tC t i ; garantie
ti
d’unicité dans un seul ObjectContainer ( mais change
si la base est défragmentée)
‰ <T> T getById(long) accès le plus rapide à un objet dont
on co
o connaît
a l’id
d ; n’active
ac e pas l’objet
obje (ga
(garde
de le
e niveau
eau
d’accès qu’il a déjà dans le cache local géré par
l’objectContainer)
Méthodes de ExtObjectContainer
j

„ Identité logique
‰ ObjectInfo getObjectInfo(objet) pour avoir la
référence à un objet géré par l’ObjectContainer
‰ La méthode Db4oUUID getUUID() de l’interface
Obj tI f retourne
ObjectInfo t l’UUID de
d l’objet
l’ bj t (garantie
( ti
d’unicité dans toutes les bases de données db4o)
‰ <T> T getByUUID(Db4oUUID)
‰ La génération d’UUID doit être configurée (méthode
generateUUID de ll’interface
interface Configuration)
Recherche p
par l’exemple
p
( Query By Example QBE)
„ L’objet passé en paramètre de
queryByExample indique les objets
recherchés
„ Ses variables d’instances qui n’ont pas la
valeur null (ou la valeur par défaut si la
variable est d’un des types primitifs Java)
forment le critère de recherche
Exemple
p
ObjectSet<Facture> factures = bd.queryByExample(new Facture("08/54", null,
null))
„ Avantage: simple
„ I
Inconvénients:
é i t
‰ Pas possible de faire une recherche des objets qui ont la valeur par
y
défaut des types primitifs
‰ Des conditions ne sont pas exprimables (pas d’autres comparaison que
l’égalité par exemple)
‰ Un constructeur qui accepte les valeurs null doit exister
‰ Impossible de faire une recherche polymorphe sous une classe abstraite
ou une interface (car pas possible de construire l’objet exemple)
Activation d’un objet
j

„ Un objet retrouvé dans la base de données et créé en


mémoire par le container est dit activé
„ T
Tous les
l objets
bj t renvoyés
é par un queryByExample/query
B E l /
sont activés
„ Activer tous les objets référencés par un objet activé
n’est pas toujours souhaitable
„ Il est possible de configurer la profondeur d’activation
d activation
lors d’une requête pour retrouver des objets de la base
Profondeur d’activation

„ Par défaut, la profondeur d’activation est 5


„ Une profondeur de 1 signifie que seul l’objet racine est
activé ; les objets qu’il référence ne sont pas créés en
mémoire centrale
„ Il est possible d’activer explicitement un objet, en
donnant la profondeur ; par exemple, si un employé emp
a été activé mais pas son département
département, le code suivant
activera le département avec une profondeur de 1 :
db activate(emp getDepartement() 1);
db.activate(emp.getDepartement(),
Activation transparente
p (1)
( )

„ Depuis la version 7 db4o peut activer


automatiquement les objets lorsque c’est utile
„ Cela signifie que les objets sont créés en
mémoire à partir des données de la base si le
code de l’application les utilise, sans que le
développeur ait à se soucier de fixer la
profondeur d’activation
Activation transparente
p (2)
( )

„ Pour cela les classes des objets persistants


doivent implémenter l’interface Activatable, ce
qui peut être fait automatiquement par un outil
fourni par db4o
„ Il faut aussi configurer la base pour qu’elle
supporte cette fonctionnalité :
Configuration configuration = Db4o.newConfiguration();
configuration.add new TransparentActivationSupport());
Persistance transparente
p (1)
( )

„ On a vu que lorsqu’une instance de classe est modifiée


et ensuite passée en paramètre de store, seules les
modifications effectuées sur l’instance
l instance elle-même
elle même sont
enregistrées dans la base
„ Par défaut
défaut, les modifications effectuées sur les instances
référencées par cette instance, et déjà gérées par db4o
ne sont pas enregistrées ; on peut cependant changer la
profondeur de modification comme on le verra dans la
section « Configuration de db4o »
Persistance transparente
p (2)
( )

„ La version 7 a ajouté la possibilité de mettre à jour


automatiquement ces instances référencées par
ll’instance
instance passée en paramètre de store
„ Les classes des instances concernées doivent
implémenter l’interface
l interface Activable
„ Il faut aussi configurer la base pour qu’elle supporte
cette
ce e fonctionnalité
o c o a é:
configuration.add new TransparentPersistenceSupport());
Interface Activatable

„ Lorsqu’un objet implémente cette interface, par


défaut il n’est pas activé : ses champs ne sont
pas initialisés
„ Lorsqu’une méthode est appelée sur cet objet,j il
doit donc être d’abord activé
„ C’est
C est pour cela que toutes les méthodes qui sont
liées à la persistance de l’objet qui implémente
cette interface doivent être modifiées pour
commencer par activer l’objet
Méthodes de l’interface Activatable

„ void bind(Activator activator) : appelée par db4o


lorsque l’instance est récupérée depuis la base, pour
associer un « activator » à l’instance
l instance
„ void activate(ActivationPurpose but) : doit être
appelée au début des méthodes de la classe en passant
comme but la valeur READ de ActivationPurpose
(pour les méthodes liées à la lecture dans la base) ou
Write (pour les méthodes liées à l’écriture)
Implémentations des méthodes de Activatable

„ Il y a une implémentation qui convient la plupart du


temps
„ L plus
Le l simple
i l estt d’d’utiliser
tili un outil
til ffournii par db4
db4o, lle
enhancer, sous la forme d’une tâche ant contenue dans
le fichier jar dont le nom se termine par « -tools tools »
„ Consultez la documentation de db4o pour plus de
p éc s o
précision
Faut-il utiliser Activatable ?

„ Cette interface facilite la tâche du développeur qui n’a


plus à positionner la profondeur d’activation ou la
profondeur de modification pour chaque cas particulier
„ Mais est-ce que les performances ne sont pas affaiblies
par cet automatisme ?
„ Et est-ce que cette facilité justifie la modification de
toutes
ou es les
es classes
c asses du modèle
odè e obje
objet ?
„ Voir aussi les problèmes exposés à l’adresse :
http://developer.db4o.com/Resources/view.aspx/Reference/Usage_Pitf
p p p g _
alls
Requêtes
q natives : Définition
„ La requête est définie dans le langage de
programmation, Java par exemple
„ A
Avantages
t :
‰ pas de nouveau langage à apprendre
‰ grande souplesse
‰ erreurs détectées à la compilation
„ Désavantage
ésa a age :
‰ peut ne pas être optimisé
Exemple
p

Predicate<Personne> predicat =
new Predicate<Personne>() {
public boolean match(Personne p) {
return p.getAge() > 60;
}
};
List<Personne> personnes =
db.query(predicat);
Tri du résultat de la recherche

„ Il est possible de passer un Comparator


(paquetage java.util ;) en paramètre de la
méthode query, avec le Predicate
„ L’ensemble
L ensemble des objets retournés sera trié en
utilisant ce Comparator
Exemple
p
Optimisation
p d’une requête
q native

„ La Façon naïve d’exécuter une requête


native :
‰ 1. récupérer tous les objets de la base
‰ 2 les passer un par un à la méthode match
2.
‰ 3. ne garder que ceux pour lesquels match
renvoie
i true
t
„ Si le nombre d’objets
j est important,
p les
performances seront catastrophiques
Optimisation
p d’une requête
q native

„ Pour obtenir de meilleures performances les


requêtes natives doivent être transformées
en requêtes SODA pour profiter des index et
des optimisations
p de db4o,, et ne p
pas avoir à
créer trop d’objets
Ecouteur p
pour requêtes
q natives

„ Permet de savoir si la requête native a été


optimisée par db4o
„ Par exemple :
Requêtes
q SODA
( Simple Object Data Acces)
„ Utilité du langage SODA
‰ Les requêtes natives sont traduites dans le langage
SODA
‰ Il peut être utile de connaître ce langage pour les cas
oùù une requête
êt native
ti ne peutt être
êt automatiquement
t ti t
optimisées ou, pour optimiser au maximum des
requêtes
„ Ce cours n’en donne qu’un rapide aperçu
Graphe
p pour
p SODA

„ L’idée de SODA est de représenter une requête


comme un arbre dont les nœuds représentent
des classes ou des champs et les arêtes
représentent des associations pour atteindre les
nœuds
„ Des contraintes associées aux nœuds indiquent
si les nœuds doivent être sélectionnés
Exemple
p

„ Pilotes dont le nom est MS :


Exemple
p plus
p complexe
p
Configuration
g de db4o

„ Il est possible de changer certains comportements de


db4o en exécutant des méthodes de la classe
Configuration
„ Il faut commencer par récupérer une instance de
Configuration :
Configuration config = Db4o.newConfiguration();
„ Après avoir modifié la configuration
configuration, on la passe à
l’ouverture de la BD par
Db4o.openFile(config, "fichier.data");
fichier.data );
Profondeur d’activation

„ Elle indique quels objets attachés à un objet


retrouvé par une requête, seront chargés en
mémoire
„ Une profondeur de 1 indique que seul l’objet
j
retrouvé sera chargé en mémoire ; les objets
associés seront remplacés par null dans l’objet
retrouvé
Imposer
p une profondeur
p d’activation

„ La valeur par défaut est 5 lors d’une interrogation de la


base
„ O peutt la
On l changer
h globalement
l b l t par
config.activationDepth(profondeur)
„ On peut aussi la changer pour tous les objets d d’une
une
classe par :
config.objectClass("UneClasse
g j ( »).minimumActivationDepth(profondeur);
) p (p );
config.objectClass("UneClasse » ).maximumActivationDepth(profondeur);
Activation des objets
j référencés

„ config.objectClass("UneClasse")
.cascadeOnActivate(true);
( );
„ config.objectClass("UneClasse")
.objectField("champ")
bj tFi ld(" h ")
.cascadeOnActivate(true);
( )
Profondeur de modification

„ Pour de meilleures performances, store


n’enregistre dans la BD que les modifications
faites sur l’objet passé en paramètre (profondeur
1)
„ Les modifications effectuées sur les objets
référencés par l’objet ne seront pas prises en
compte (voir l’exemple plus loin)
Configuration
g de la profondeur
p de
modification
„ Il est possible de modifier ce comportement :
‰ mise à jour des objets référencés :
config.objectClass(UneClasse.class)
fi bj tCl (U Cl l )
cascadeOnUpdate(true)
‰ profonde r de 2 :
profondeur
config.objectClass(UneClasse.class)
.updateDepth(2)
updateDepth(2)
Index

„ Pour les grands ensembles de données, il est


possible d’accélérer des requêtes en indiquant
que des index devront être construits sur
certains champs :
config.objectClass("UneClasse")
.objectField( UnChamp )
.objectField("UnChamp")
.indexed(true)
Concurrence

„ Niveau d’isolation : Il n’est pas possible de


choisir un autre niveau que le niveau read
committed
„ Gestion des collisions
‰ Gestion optimiste, par exemple en utilisant
peekPersisted pour vérifier au dernier moment si
on a eu raison d’être optimiste (le code vérifie
certaines données qui n’ont pas été modifiées par une
autre transaction depuis le début du traitement)
‰ Gestion pessimiste, par l’application car il n’est pas
possible de bloquer des données dans la BD
Gestion pessimiste
p

„ Il faut utiliser des sémaphores liés à db4o pour créer des


sections critiques dans le code
„ U sémaphore
Un é h estt repéré
é é par un nom (d
(de ttype String)
St i )
„ Les sections de code critiques doivent être encadrées
par les appels des méthodes de
ExtObjectSemaphore
boolean setSemaphore(nom,
setSemaphore(nom timeout) et
void releaseSemaphore(nom)
Sémaphores
p

„ Le 2ème paramètre de la méthode setSemaphore


indique combien de millisecondes il faut attendre pour
qu’une
qu une autre transaction relâche le sémaphore
„ La méthode renvoie true si le code possédait déjà le
sémaphore ou s’il
s il a pu l’acquérir
l acquérir dans le délai indiqué ;
elle renvoie false sinon
„ Un sé
U sémaphore
ap o e esest relâché
e âc é pa
par u
un appe
appel à
releaseSemaphore ou lorsque l’objectContainer est
fermé
Protection d’un objet
j

„ Il est possible d’utiliser plusieurs sémaphores


„ Pour p protéger
g un objet,
j , une astuce est
d’utiliser un sémaphore dont le nom contient
ll’identificateur
identificateur de l’objet
l objet (obtenu par
objectContainer.getId())
Exemple
p
Gestion des versions

„ Refactoring automatique:
„ db4o sait p
prendre en charge
g les modifications
suivantes :
‰ ajouter
j une interface à une classe
‰ supprimer un champ dans une classe
‰ ajouter
j un champ p
‰ changer le type d’un champ
‰ renommer un champ p
‰ renommer une classe
Supprimer/ajouter
pp j un champ
p

„ Il n’y a rien à faire


„ Les données déjà j enregistrés
g dans la base
(avec l’ancienne définition) seront récupérées
sous la forme d’objets j de la nouvelle définition ;
l’ancien champ sera ignoré
„ Idem pour l’ajout
l ajout ; les anciennes données seront
récupérées comme des objets de la nouvelle
classe ; le nouveau champ aura la valeur null ou
0
Renommer un champ
p ou une classe

„ Il faut lancer une commande (une seule fois)


pour que db4o soit au courant de la modification
„ configuration.objectClass("p.class")
rename("nouvPaquetage
( g nouvClasse"))
.nouvPaquetage.
„ configuration.objectClass( p.class )
configuration.objectClass("p.class")
.objectField("ancienChamp")
.rename( nouvChamp )
.rename("nouvChamp")
Changer
g le type
yp d’un champ
p

„ db4o ajoute un nouveau champ


„ L’ancien champ p est conservé et la base p
peut
alors fonctionner avec les 2 versions de la
classe (j(jusqu’à la prochaine défragmentation
g de
la base)
„ Il faut écrire un programme qui recopie les
anciennes données (avec conversion de type)
dans le nouveau champ db4o
Exemple
p pour
p changer
g le type
yp d’un champ
p

„ L’exemple (tiré du manuel de référence de


db4o)) montre comment récupérerp les
noms de pilotes qui sont dans un champ
nom
„ Ce champ nom était avant de type String
et il devient du type Identite
Exemple
p pour
p changer
g le type
yp d’un champ
p
Exemple
p pour
p changer
g le type
yp d’un champ
p
Problèmes avec db4o

„ Manque de fonctionnalités :
‰ Le code de l’application doit prendre en charge des
f
fonctionnalités
ti lité quii sontt remplies
li par lles SGBDR :
‰ pas de contraintes de clé primaire et de référence –

ll’application
application doit faire attention à ne pas dupliquer les
objets
‰ pas de blocage des objets de la BD – ll’application
application doit
créer des sections critiques
Optimisation
p des requêtes
q natives

„ Impossible dès que la requête est trop


p
complexe
„ Idem le moteur SQL des premiers temps
des SGBDR (améliorations à venir
venir,
comme pour les moteurs des SGBDR ?)
Configuration spéciale pour la persistance (1)

„ Configurations spéciales indispensables pour la


sauvegarde de certaines classes comme par exemple
Calendar ou BigDecimal
„ En effet par défaut db4o n’utilise pas les constructeurs
des classes pour construire en mémoire centrale les
objets récupérés depuis la base de données
„ Certains
Ce a s cchamps
a ps ttransient
a s e t de l’objet
obje peu
peuvent
e a alors
o s ne
e
pas être initialisés
Configuration spéciale pour la persistance (2)

„ 2 solutions p
possibles ((à tester sur chaque
q classe
particulière) :
‰ avant la lecture dans la base de données, indiquer à

db4o qu’il faut passer par un constructeur pour créer


les objets de ces classes
configuration.objectClass(Calendar.class)
.callConstructor(true);
‰ avant l’écriture dans la base de données, indiquer à

db4o qu’il faut enregistrer dans la base les champs


transients
configuration.objectClass(BigDecimal.class)
.storeTransientFields(true);
storeTransientFields(tr e)
Problème avec le cache
„ Quelquefois une requête ne rend pas ce qui est dans la
BD
„ E effet,
En ff t l’ObjectContainer
l’Obj tC t i utilise
tili un cacheh d des objets
bj t
qu’il a déjà utilisés et les renvoie s’ils sont concernés par
une requête
„ Dans l’exemple suivant, le nouvel âge de Sophie
Dupond
upo d n’a a pas é
été
éeenregistré
eg s é dadans
s la
a base malgré
a g é ce
que le résultat de la requête pourrait le laisser croire
Exemple
p de problème
p 1/2
// Récupère Monsieur Dupond
List<Personne> liste =
bd.query(new Predicate<Personne>() {
public boolean match(Personne p) {
return p.getNom().equals("Dupond")
&& p.getSexe().equals("M");
}
});
Personne p = liste.get(0);
Personne sophie = p.getEpouse();
Exemple
p de problème
p 2/2
// Sophie avait 25 ans; elle passe à 26 ans
sophie.setAge(sophie.getAge() + 1);
// Enregistre modifications sur Mr Dupond
bd.store(p);
bd.commit();
// Est-ce que âge de Sophie est OK ?
// Affiche 26 alors que c’est 25 dans BD
sophie = (Personne)db.queryByExample(
new Personne("Sophie", "Dupond")).next();
System.out.println(sophie.getAge());
Éviter ce problème
p

„ Il faut utiliser refresh :


sophie
p = ((Personne)db.queryByExample
) q y y p (
new Personne("Sophie","Dupond"))
.next();
t()
bd.refresh(sophie);
( ) ( p ));
// Affiche 25 et pas 26
System out println(sophie getAge());
System.out.println(sophie.getAge());