Esistono diverse opzioni per integrare Redis in un proprio progetto Java. Le tre librerie "raccomandate" (contrassegnate con una stella dorata nella pagina ufficiale dei client per Redis) sono:
- Lettuce, che fa delle alte prestazioni e dell'asincronia la propria bandiera;
- Redisson, che permette di sfruttare strutture dati, altamente scalabili, basate su
Redis; - Jedis, uno dei primi e probabilmente più conosciuti client Java per Redis. Questa è proprio l'opzione che sfrutteremo nel resto della lezione.
Integrare Jedis
Jedis può essere integrato velocemente in un progetto Java mediante Maven. È sufficiente inserire nel file pom.xml la seguente direttiva:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
Per iniziare ad utilizzarlo, è sufficiente istanziare un oggetto di classe Jedis
i cui argomenti saranno l'indirizzo IP (o l'host) e la porta TCP. Qualora questi non venissero specificati, si utilizzerebbero i valori di default (localhost/6379):
Jedis jedis = new Jedis("192.168.56.3", 5555);
Se necessario, si potrà direttamente fornire la password per l'autenticazione con il metodo auth()
:
jedis.auth("parolasegreta");
Utilizzare valori semplici
Una delle caratteristiche che contraddistingue Jedis è l'immediatezza nel suo apprendimento: i metodi disponibili, per la maggior parte, hanno nome analogo alla corrispondente funzione Redis. Per iniziare, possiamo inserire valori semplici in un database sfruttando, rispettivamente, i metodi set()
e get()
:
jedis.set("unValore", "1000");
jedis.set("unNome", "Giovanni");
System.out.println(jedis.get("unValore"));
// stampa 1000
System.out.println(jedis.get("unNome"));
// stampa Giovanni
Ricordiamo che in Redis il tipo "stringa" viene impiegato per tutti i tipi di dato semplici, pertanto il metodo set()
accetta delle stringhe per qualsiasi tipo di valore. Il numero 1000 passato nella prima invocazione può essere utilizzato come un numero, infatti incrementandolo di 1 (mediante incr()
) e di 6 (mediante incrBy()
) il suo valore non otterremmo errori e aggiorneremmo il suo corrispettivo a 1007:
jedis.incr("unValore");
// unValore vale 1001
jedis.incrBy("unValore", 6);
// unValore vale 1007
Qualora applicassimo i medesimi metodi alla chiave unNome otterremmo in risposta un'eccezione di classe JedisDataException
corredata dal messaggio ERR value is not an integer or out of range.
Si possono inoltre utilizzare le chiavi a scadenza, particolarmente utili in applicazioni molto dinamiche. La seguente riga di codice imposta il valore "Milano" per la chiave "città" che rimarrà accessibile per 10 secondi:
jedis.setex("citta", 10, "Milano");
Le liste
Considerata la comune utilità di array e liste in Java, è facile immaginare quanto il corrispondente Redis possa essere utilizzato in applicazioni basate su questo DBMS. Con il seguente codice creiamo la lista aula01 che contiene un elenco di allievi:
jedis.lpush("aula01", "Rossi Andrea", "Verdi Simone", "Gialli Lorenzo", "Bianchi Sabrina");
Con lpush()
i valori vengono inseriti a sinistra pertanto troveremo "Bianchi Sabrina" in prima posizione in quanto inserita per ultima. La struttura dati può essere messa alla prova in questo modo:
jedis.llen("aula01");
// restituisce 4 .... la dimensione della lista
jedis.lindex("aula01", 3);
// restituisce "Rossi Andrea" .... legge il quarto elemento della lista (ma non lo elimina)
jedis.lpop("aula01");
// restituisce ed elimina "Bianchi Sabrina", il primo elemento a sinistra nella lista
Le mappe
Per creare una struttura a mappa, possiamo invocare più volte il metodo hset()
in riferimento alla stessa chiave:
jedis.hset("studente", "nome", "Andrea");
jedis.hset("studente", "cognome", "Verdi");
jedis.hset("studente", "eta", "28");
In questo caso, abbiamo creato una chiave "studente" alla quale abbiamo associato una mappa di tre entry con chiavi "nome", "cognome" ed
"eta" valorizzate, rispettivamente, a "Andrea", "Rossi" e "28". Con il metodo hget()
, possiamo richiedere uno dei valori in essi inseriti purchè si fornisca come argomento anche la chiave interna alla mappa:
String nome = jedis.hget("studente", "nome");
// l'oggetto nome di tipo String vale "Andrea"
Come si vede, il singolo valore è stato migrato all'interno di una stringa. Con hgetAll()
possiamo eseguire una vera trasposizione della struttura dati in un oggetto Map
di Java:
Map<String, String> unoStudente = jedis.hgetAll("studente");
// tutta la mappa "studente" è stata migrata in una mappa Java
unoStudente.get("nome"));
// restituisce "Andrea"
unoStudente.get("cognome"));
// restituisce "Verdi"
unoStudente.get("eta"));
// restituisce "28"
Un'altra opzione interessante vede la conservazione delle chiavi di strutture dati Redis in altre strutture. Ad esempio, possiamo immaginare di organizzare i dati relativi ad un corso all'interno di una mappa. Le informazioni concernenti il docente, l'anno accadamico o l'aula di svolgimento possono essere conservate come normali stringhe ma l'elenco di allievi sarà costituito a sua volta da un'ulteriore struttura dati, una lista. Pertanto potremmo registrare gli allievi in questo modo:
jedis.lpush("allievi", "Rossi Andrea", "Verdi Simone", "Gialli Lorenzo", "Bianchi Sabrina");
ed immagazzinare la chiave corrispondente tra i dati presenti in una mappa:
jedis.hset("corso_storia", "docente", "Ivano Verdi");
jedis.hset("corso_storia", "aula", "14A");
jedis.hset("corso_storia", "anno", "2018");
jedis.hset("corso_storia", "partecipanti", "allievi");
L'ultima invocazione a hset()
immette come valore "allievi" ossia la chiave della lista di studenti iscritti al corso. Qualora volessimo recuperare il terzo studente registrato potremmo utilizzare la seguente invocazione:
String terzo_allievo=jedis.lindex(jedis.hget("corso_storia", "partecipanti"), 2);
Con un accesso alla mappa si recupera la chiave della lista e con uno successivo a quest'ultima si ottiene nome e
cognome dell'allievo: sarà stampato in questo caso "Verdi Simone" (ricordare che i dati immessi in lista con lpush()
vengono collocati in testa).
Ulteriori strutture dati
Lo studio di Jedis non è a questo punto finito di certo. Si potrà proseguire con le ulteriori strutture dati disponibili. Dopo aver preso una certa confidenza con queste tramite console interattiva il loro utilizzo in Java non si discosterà molto e sarà possibile integrarle velocemente nei propri programmi.