Forse molti di voi si sono sempre chiesti come sia possibile distribuire un’applicazione (non per forza in Java) che sfrutta un sistema di database. Bene, ciò è intuitivo per importanti applicazioni enterprise o applicazioni web, in quanto spesso si presuppone che il deploy dell’applicazione avverrà in un ambiente preparato ad hoc per l’applicazioni, ad esempio un server.
Pensiamo però ad una semplice applicazione di gestione di una qualche risorsa, una semplice applicazione desktop, come può essere un mediaplayer con funzionalità di catalogazione dei file musicali, o un software per la gestione dei libri nella libreria di casa, o, ancora, un software per la gestione delle proprie fotografie.
Ovviamente anche queste applicazioni si appoggiano ad un database, in quanto la gestione dei dati tramite SQL risulta molto più efficiente che tramite un semplice file. Inoltre è possibile delegare al DBMS i compiti più ostici, come la gestione della concorrenza nell’accesso ai dati.
Queste le premesse, ma come posso distribuire un’applicazione del genere senza dover distribuire assieme anche il DBMS, come ad es. MySQL? Non possiamo supporre che l’utente che installerà il nostro software abbia già installato il DBMS che noi richiediamo, e non possiamo nemmeno obbligarlo ad installarlo. Oppure può capitare che l’utente abbia il DBMS già installato, e quindi non possiamo installarlo una seconda volta, e il nostro software avrebbe bisogno di essere configurato per l’uso del DBMS esistente, che magari è in una versione non adatta.
Nel prossimo paragrafo la soluzione!
SQLite, il DBMS integrabile nell’applicazione
SQLite è una libreria dll scritta in C/C++ che offre tutte le funzionalità di un classico DBMS. Innanzitutto bisogna specificare che è OpenSource, cosa che non guasta mai!
La vera manna dal cielo è il fatto che, essendo una libreria, SQLite può essere integrato direttamente nell’applicazione, in quanto non è un processo esterno ad essa.
Peccato che a noi interessi Java, e non C++. Esistono a tale scopo numerosi bindings per altrettanti linguaggi di programmazione, come Java, Lisp, Fortran, Php, ecc…
In pratica SQLite permette di essere interrogata tramite la sintassi standard di SQL-92 e salva la base di dati in un file. Tutto avviene all’interno della nostra applicazione.
Alcune operazioni in realtà non sono possibili, ma probabilmente in futuro implementate. Ad esempio non è disponibile il RIGHT OUTER JOIN, alcune specifiche istruzioni per il comando ALTER TABLE, la scrittura delle VIEWS, che sono disponibili ma solo in lettura.
I limiti sono veramente pochi. Intanto, non esistendo comunicazione inter-process, come avviene invece con i normali DBMS, si ha una velocità di scambio dati tra il DB e l’applicazione molto maggiore. La dimensione della base di dati è "limitata" a qualche terabyte di dati, più che sufficiente per le normali applicazioni.
La politica di SQLite è quella di evitare i limiti. Ciò porta benefici (non ci sono limiti) e problemi (senza conoscere i limiti non è possibile testare SQLite al limite delle possibilità). In generale secondo SQLite se qualcosa trova abbastanza spazio nella memoria della macchina, e se è possibile indirizzarla con 32 bit, allora dovrebbe funzionare.
In ogni caso per saperne di più sui bindings disponibili per altri linguaggi di programmazione, e sulle operazioni ancora non implementate, visitate il sito ufficiale www.sqlite.org.
Non pensate che SQLite sia l’ennesima libreria raffazzonata per svolgere operazioni in realtà impossibili. SQLite affronta il problema dei dati in modo diverso dai classici DMBS, ma non per questo si tratta di una libreria inutile o di bassa qualità, anzi. Giusto per dare un’idea, date un’occhiata alla lista dei nomi importanti che utilizzano SQLite. Tra essi spiccano Google, Sun, Adobe, Microsoft, ecc…
Il binding per Java
Specifico subito che esistono molti bindings per Java, tutti disponibili dal sito ufficiali. In generale esistono i bindings native e quelli 100% Java. I primi sfruttano la dll originale di SQLite, e forniscono solo un’interfaccia a tale dll tramite una libreria jar. I bindigs 100% invece hanno prestazioni leggermente minori, ma hanno il vantaggio di essere totalmente multipiattaforma, proprio perchè 100% Java.
Anche i metodi di comunicazione possono essere diversi. In questo tutorial vedremo come utilizzare un binding 100% Java a cui si può accedere con il classico JDBC, e quindi il package java.sql.
Il binding in questione è fornito da Zentus. Scaricate il binding Pure Java, otterrete il file sqlitejdbc-vXXX-nested.tgz, dove XXX indica la versione, al momento 037. Mi è capitato, su Windows, che il file scaricato sia un .tar. In questo caso lo scompattamento produce un solo file. Ciò è scorretto, quindi in questo caso rinominate il file .tar in .tgz. Dopodichè scompattate il file. Si ottengono i file README (classico) e sqlitejdbc-vXXX-nested.jar. Date un’occhiata al file README, che contiene anche un esmpio di utilizzo della libreria. Quello che ci interessa è però il .jar.
Per fare subito un test prendete il .jar e inseritelo nella directory root della vostra applicazione. Ora aggiungete il file al CLASSPATH dell’applicazione. Finito!
Creiamo questa classe di prova:
import java.sql.*;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement stat = conn.createStatement();
stat.executeUpdate("create table people (name, occupation)");
stat.executeUpdate("insert into people (name, occupation) VALUES ('Gandhi', 'politics')");
stat.executeUpdate("insert into people (name, occupation) VALUES ('Turing', 'computers')");
stat.executeUpdate("insert into people (name, occupation) VALUES ('Wittgenstein', 'smartypants')");
ResultSet rs = stat.executeQuery("select * from people");
while (rs.next()) {
System.out.println("name = " + rs.getString("name"));
System.out.println("occupation = " + rs.getString("occupation"));
}
rs.close();
conn.close();
}
}
In pratica cerchiamo la classe org.sqllite.JDBC e creiamo una connessione al file database test.db. Se il file non esiste viene creato. Dopodichè possiamo eseguire tutte le normali query SQL come facciamo con qualsiasi DB tramite JDBC.
Ecco fatto! La nostra applicazione include il suo DBMS per gestire i dati dell’applicazione. Provate a pensare l’utilità per avere file di dati prorpietari per l’applicazione e i suoi mille altri usi!