Calypte é uma ótima opção de cache para aplicações Java. Ele é extremamente rápido, trabalha bem com pouca memória, permite o armazenamento de dados em memória secundária e tem suporte transacional.
O Calypte pode ser instalado usando o Maven ou fazendo o download dos binários e configurando-o no classpath da aplicação.
Se for utilizado o Maven, deve ser informado no
pom.xml:
<repositories> <repository> <id>calypte-repo</id> <name>Calypte repository.</name> <url>https://calypte.sourceforge.io/maven/2</url> </repository> </repositories> ... <dependency> <groupId>calypte</groupId> <artifactId>jcalypte</artifactId> <version>1.0.2.0</version> </dependency>
As operações no cache são feitas com o uso da classe
CalypteConnection
. Ela fica localizada no pacote calypte
e é
obtida a partir de uma instância da CalypteConnectionPool
.
CalypteConnection
possui os seguintes métodos:
public interface CalypteConnection { void close() throws CacheException; boolean isClosed(); boolean replace( String key, Object value, long timeToLive, long timeToIdle) throws CacheException; boolean replace( String key, Object oldValue, Object newValue, long timeToLive, long timeToIdle) throws CacheException; Object putIfAbsent( String key, Object value, long timeToLive, long timeToIdle) throws CacheException; boolean set( String key, Object value, long timeToLive, long timeToIdle) throws CacheException; boolean put(String key, Object value, long timeToLive, long timeToIdle) throws CacheException; Object get(String key, boolean forUpdate) throws CacheException; Object get(String key) throws CacheException; boolean remove( String key, Object value) throws CacheException; boolean remove(String key) throws CacheException; void setAutoCommit(boolean value) throws CacheException; boolean isAutoCommit() throws CacheException; void commit() throws CacheException; void rollback() throws CacheException; String getHost(); int getPort(); }
A CalypteConnectionPool
faz o gerenciamento e provê as conexões com o cache.
Ele mantém uma certa quantidade de conexões ativas e limita a criação de novas conexões
utilizando as conexões atualmente ativas. Isto permite uma melhor utilização dos recursos.
CalypteConnectionPool
possui os seguintes métodos:
public class CalypteConnectionPool { public CalypteConnection getConnection() throws CacheException {...} public CalypteConnection tryGetConnection(long l, TimeUnit tu) throws CacheException {...} public void shutdown() {...} }
CalypteConnectionPool pool = new CalypteConnectionPool("localhost", 1044, 1, 50); CalypteConnection con = null; try{ con = pool.getConnection(); ... con.put(key, value, 0, 0); } finally{ if(con != null){ con.close(); } }
Também é possível criar uma conexão direta com o cache. Nesse caso, ela não será gerenciada!
CalypteConnection con = new CalypteConnectionImp(SERVER_HOST, SERVER_PORT); ... con.close();
São oferecidos vários métodos para inserir um item no cache. Cada um com sua particularidade.
O método put
associa um valor a uma chave, mesmo que ela exista.
Retorna true
, se o valor for substituído, ou
false
, se não existir um valor associado à chave.
if(con.put(key, value)){ System.out.println("replaced"); } else{ System.out.println("stored"); }
O método replace
substitui o valor associado à chave somente
se ele existir. Ele retorna true
, se o valor for substituído, ou
false
, se o valor não for armazenado.
if(con.replace(key, value)){ System.out.println("replaced"); } else{ System.out.println("not stored"); }
Também é possível substituir o valor associado à chave somente se ele for igual a um determinado valor.
if(con.replace(key, oldValue, value)){ System.out.println("replaced"); } else{ System.out.println("not stored"); }
O método putIfAbsent
associa o valor à chave somente se a chave não estiver
associada a um valor. Retorna o valor associado à chave ou null
, se não existir
um valor associado à chave. Esse método tem uma particularidade. Quando existe um valor associado
à chave, o mesmo é retornado, mas será lançada uma exceção se ele expirar no momento em que
for recuperado.
try{ Object currentValue = con.putIfAbsent(key, value); if(currentValue == null){ System.out.println("stored"); } else{ System.out.println("not stored"); } } catch(CacheException $e){ if(e.getCode() == 1030){ //o valor atual expirou } throw e; }
O método set
associa o valor à chave somente se a chave não estiver associada a um
valor. Ele retorna true
, se o valor for associado à chave, ou false
, se
ele for descartado.
if(con.set(key, value)){ System.out.println("stored"); } else{ System.out.println("not stored"); }
Um valor é obtido com o uso do método get
.
Ele retorna o valor associado à chave ou null
,
se não existir um valor associado.
Object value = con.get(key); if(value != null){ System.out.println("value exists"); } else{ System.out.println("value not found"); }
São oferecidos vários métodos para remover um item do cache.
O método remove
apaga o valor associado à chave. Ele retorna true
,
se o valor for removido, ou false
, se ele não existir.
if(con.remove(key)){ System.out.println("removed"); } else{ System.out.println("not found"); }
Também é possível remover o valor associado à chave somente se ele for igual a um determinado valor.
if(con.remove(key, value)){ System.out.println("removed"); } else{ System.out.println("not found"); }
Uma transação é iniciada com o uso do método
setAutoCommit()
com o parâmetro igual a false e finalizada com o
método commit()
, rollback()
ou setAutoCommit()
com o parâmetro true
.
O método setAutoCommit()
define o modo de confirmação
automática. Se o modo de confirmação automática estiver ligado,
todas as operações serão tratadas como transações individuais. Caso
contrário, as operações serão agrupadas em uma transação que
deve ser confirmada com o método commit()
ou descartadas com o
método rollback
. Por padrão, cada nova conexão inicia com
o modo de confirmação automática ligada.
//inicia a transação desligando o modo de confirmação automática. con.setAutoCommit(false); ... //confirma todas as operações ligando o modo de confirmação automática. con.setAutoCommit(true);
O método commit()
confirma todas as operações da transação
atual e libera todos os bloqueios detidos pela atual sessão.
//inicia a transação. con.setAutoCommit(false); ... //confirma todas as operações. con.commit();
O método rollback()
desfaz todas as operações da transação
atual e libera todos os bloqueios detidos pela atual sessão.
try{ //inicia a transação. con.setAutoCommit(false); ... //confirma todas as operações. con.commit(); } catch(Exception e){ //Desfaz todas as operações. con.rollback(); }
Para resolver o problema de leitura fantasma e leitura não repetitiva, é oferecida a opção de bloquear um determinado item no momento de sua seleção. A opção é o parâmetro forUpdate do método get.
No exemplo abaixo, depois que o método get()
é
executado, o item key fica bloqueado até que o método commit()
ou
rollback()
seja executado.
try{ //inicia a transação. con.setAutoCommit(false); //bloqueia o item key. value = con.get(key, true); if(value != null && value.equals(value2)){ //remove o item key se existir e for igual ao valor 'val' con.remove(key); } //confirma todas as operações. con.commit(); } catch(Exception e){ //Desfaz todas as operações. con.rollback(); }