Questa lezione illustra due argomenti di notevole interesse per un uso avanzato del DBMS:
le transazioni - non sempre presenti nei prodotti NoSQL - e gli hook, corrispondenti al concetto di
trigger del mondo relazionale. Si tratta di due meccanismi piuttosto diversi tra loro ma accomunati
dalle medesime finalità: concorrere all'integrità e alla consistenza dei dati.
Transazioni
Con il termine transazione, si indica una sessione di comandi da eseguire nel database, i
cui risultati devono essere resi persistenti solo in caso di assenza totale di errori; altrimenti
devono essere annullati tutti. Nella teoria delle basi di dati, si dice che una transazione deve
rispettare quattro proprietà, chiamate in genere proprietà "acide" dall'acronimo ACID (Atomicity,
Consistency, Isolation, Durability):
- atomicità: le operazioni che compongono una transazione non possono essere completate
parzialmente: o hanno successo tutte o vengono annullate tutte; - consistenza: la transazione deve mantenere l'integrità dei dati e rispettarne i vincoli
referenziali; - isolamento: finchè la transazione non si è conclusa, i suoi risultati parziali non devono
essere visibili alle altre transazioni; - durevolezza: i risultati finali di una transazione andata a buon fine devono essere salvati
in maniera persistente su un database.
OrientDB garantisce le proprietà acide, e pertanto può essere considerato un sistema realmente
transazionale.
Una transazione si articola lungo le seguenti fasi:
- inizio della transazione: deve essere sempre comunicato tramite il comando BEGIN. Una volta
impartito tale comando, OrientDB riferirà che la transazione ha avuto inizio ed è contraddistinta
da un numero di riconoscimento; - avviata la transazione possono essere svolte le diverse operazioni che la
compongono.
Esse consistono in normali comandi SQL, con la differenza che fanno tutti parte di un'unica
sessione di lavoro finchè la transazione non termina; - per terminare la transazione, si può scegliere di salvare definitivamente i risultati, se tutto
si è svolto correttamente, ed in questo caso si impartirà il comando COMMIT. Altrimenti, si potrà
annullare l'intera sessione con il comando ROLLBACK.
È importante ricordare che un client può svolgere una transazione alla volta, e ciò si può
verificare impartendo due comandi BEGIN
in successione: il secondo fallirà ed il messagio di errore
avviserà che una transazione è già in corso ed un nuovo BEGIN
potrà verificarsi solo dopo un
COMMIT
o un ROLLBACK
.
Hook
Gli hook sono delle procedure che scattano "ad eventi", permettono in pratica di definire un'azione
che deve essere svolta al verificarsi di una qualunque delle possibili azioni CRUD. Gli hook
sono l'applicazione in OrientDB dei più noti trigger del mondo relazionale.
Esistono due tipi di hook:
- Dynamic Hook, definiti a livello di database o singolo
documento, più flessibili ma anche meno performanti; - Native Hook, scritti direttamente
come classi Java, decisamente più veloci dei primi.
Quando si creano degli hook dinamici a livello di classe si devono compiere tre passi. Per prima cosa,
è necessario creare una classe che estenda la superclasse OTriggered
:
CREATE CLASS Persona EXTENDS OTriggered
La classe Persona
che abbiamo creato potrà contenere dei normali documenti, ma al contempo
sarà automaticamente predisposta per poter attivare delle funzioni su evento. Per definire quale
sia l'evento, è necessario modificare la classe. Gli eventi possibili sono i seguenti:
Evento | Descrizione |
---|---|
onBeforeCreate |
Generato prima della creazione di un nuovo documento |
onAfterCreate |
Generato dopo la creazione di un documento |
onBeforeRead |
Generato prima della lettura di un documento |
onAfterRead |
Generato dopo la lettura di un documento |
onBeforeUpdate |
Generato prima della modifica di un documento |
onAfterUpdate |
Generato dopo la modifica di un documento |
onBeforeDelete |
Generato prima della cancellazione di un documento |
onAfterDelete |
Generato dopo la lettura di un documento |
Come si nota, gli eventi sono otto: quattro di tipo After e quattro di tipo Before. Ogni
coppia After/Before esiste per ognuna delle quattro operazioni CRUD, e pertanto esisterà ogni possibile
evento da attivare prima o dopo che uno o più documenti della classe vengano sottoposti ad una
qualunque operazione. All'evento prescelto, è necessario associare solo una funzione da attivare:
ALTER CLASS Persona CUSTOM onAfterDelete=suDocumentoCancellato
A seguito del comando precedente, tutte le volte che viene cancellato un documento della classe sarà eseguita la
funzione suDocumentoCancellato
. OrientDB permette di creare funzioni in qualunque linguaggio supportato
dal suo motore o dalla Java Virtual Machine. In questo caso, per prova, eseguiremo una funzione
Javascript molto semplice:
CREATE FUNCTION suDocumentoCancellato
"print('Un documento è stato cancellato dalla classe Persona')"
LANGUAGE Javascript
L'istruzione print
riportata tra virgolette costituisce il corpo della funzione e non farà
altro che stampare un messaggio nella finestra del server (si faccia bene attenzione: la finestra
del server, non quella dove state eseguendo la console).
Per provare l'hook appena creato, sarà sufficiente far scattare l'evento cancellando un documento
dalla classe Persona
e controllando se, nella finestra in cui avete attivato il server, il messaggio
è stato stampato.
Per poter controllare il corretto funzionamento di un hook, conviene verificare prima che la
funzione collegata faccia bene il suo lavoro. Come si è spiegato in una lezione precedente, esiste
un ambiente comodo per la scrittura ed il debug delle funzioni all'interno del client visuale Studio.
Vi si può accedere tramite la schermata Functions, e sarà il luogo in cui lavorare alle proprie
funzioni, in qualunque linguaggio siano scritte. Inoltre, qui dovrebbero essere visualizzate
anche le funzioni definite tramite console con CREATE FUNCTION
, come fatto poc'anzi.
Come si è visto, i Dynamic Hook non sono particolarmente difficili da configurare. La loro pecca
risiede nelle performance non del tutto ottimali. Migliori prestazioni possono aversi con i
Native Hook che devono essere implementati in Java e pertanto esulano dagli scopi di questa lezione:
indicazioni dettagliate in merito possono essere reperite sulla
documentazione ufficiale.