Back-End

15 fev, 2018

Trabalhando com Redis no Java

Publicidade

Redis é uma estrutura de armazenamento de dados open source, baseado no conceito de chave e valor. Seus dados são salvos em memória, possuindo a opção de informar o tempo de vida da chave, além de ter diversos tipos de estruturas para armazenamento. Para saber mais e entrar a fundo no conceito e utilização do Redis, você pode conferir neste artigo.

Para maior facilidade e comodidade na demonstração da utilização de Redis com Java, a instalação pode ser realizada via Docker, através do seguinte comando:

docker run --name redis -p 6379:6379 -d redis

Integração com Java

Para a demonstração de Redis com Java, será utilizado o JNoSQL, um framework que abstrai toda a comunicação com os diferentes tipos de bancos NoSQL, da mesma forma que todos estão acostumados com o JPA nos bancos relacionais. Caso você queria saber mais a respeito do JNoSQL, pode conferir através deste artigo.

Para este exemplo, você precisará utilizar Java 8, ou superior e CDI. Além desses requisitos, assim como em todo projeto, é necessário declarar as dependências a serem utilizadas.

<properties>
        <maven.compile.targetLevel>1.8</maven.compile.targetLevel>
        <maven.compile.sourceLevel>1.8</maven.compile.sourceLevel>
        <maven.compile.version>3.5.1</maven.compile.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <json.b.version>1.0.1</json.b.version>
        <javax.json.version>1.1</javax.json.version>
        <javax.json.bind>1.0</javax.json.bind>
        <jnosql.version>0.0.4-SNAPSHOT</jnosql.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.jboss.weld.se</groupId>
            <artifactId>weld-se-shaded</artifactId>
            <version>3.0.1.Final</version>
        </dependency>
        <dependency>
            <groupId>javax.json</groupId>
            <artifactId>javax.json-api</artifactId>
            <version>${javax.json.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.json.bind</groupId>
            <artifactId>javax.json.bind-api</artifactId>
            <version>${javax.json.bind}</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse</groupId>
            <artifactId>yasson</artifactId>
            <version>${json.b.version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>javax.json</artifactId>
            <version>${javax.json.version}</version>
        </dependency>

        <dependency>
            <groupId>org.jnosql.artemis</groupId>
            <artifactId>artemis-key-value</artifactId>
            <version>${jnosql.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jnosql.diana</groupId>
            <artifactId>redis-driver</artifactId>
            <version>${jnosql.version}</version>
        </dependency>
    </dependencies>

Nas dependências é possível ver que é utilizado o JSON-B, a especificação Java para padronização de serialização e desserialização de JSON. Isso é devido o funcionamento do JNoSQL, pois no Redis todos os valores são tratados como String, dessa forma, se for informado um valor que seja diferente de uma String, ele irá transformar para JSON.

Utilização

Antes de começar, é preciso configurar os Producers do nosso bucket, list, set, etc. As configurações podem ser conferidas nessa classe.

Como classe modelo, será utilizada a seguinte:

@Entity
public class God implements Serializable {
    @Id
    private String id;
    private String power;
    private Set<String> duties;
    @JsonbCreator
    public God(@JsonbProperty("id") String id,
        @JsonbProperty("power")String power,
        @JsonbProperty("duties")Set<String> duties) {
        this.id = requireNonNull(id, "id is required");
        this.power = requireNonNull(power, "power is required");
        this.duties = requireNonNull(duty, "duties is required");
    }
}

Nessa classe, é possível visualizar a integração entre JNoSQL (@Entity, @Id) e JSON-B (@JsonbCreator, @JsonbProperty).

Para realizar a manipulação, é possível através de duas formas, por Template ou Repository.

Template

public class Main {
    public static void main (String[] args) {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            Set<String> duties = new HashSet<>();
            duties.add("music");
            duties.add("poetry");
            duties.add("medicine");
            God apollo = God.builder()
                    .id("Apollo")
                    .power("Sun")
                    .duties(duties)
                    .build();
            KeyValueTemplate keyValueTemplate = container.select(KeyValueTemplate.class).get();
            God godSaved = keyValueTemplate.put(apollo);
            System.out.println(godSaved);
            Optional<God> godFound = keyValueTemplate.get("Apollo", God.class);
            System.out.println(godFound);
        }
    }
}

Repository

public class Main2 {
    public static void main (String[] args) {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            Set<String> duties = new HashSet<>();
            duties.add("moon");
            duties.add("hunt");
            God artemis = God.builder()
                    .id("artemis")
                    .power("archery")
                    .duties(duties)
                    .build();
            GodRepository repository = container.select(GodRepository.class, DatabaseQualifier.ofKeyValue()).get();
            God godSaved = repository.save(artemis);
            System.out.println(godSaved);
            Optional<God> godFound = repository.findById("artemis");
            System.out.println(godFound);
        }
    }
}

Estruturas Padrões

Para facilitar a vida dos desenvolvedores Java, as estruturas padrões foram abstraídas através do Redis, assim, ao trabalhar com uma lista, conjunto do Jedis ou outra estrutura, você irá manipular de forma transparente através das classes Java, como é o caso do List, Set, Queue e Map.

List

public class Main3 {
    public static void main (String[] args) {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            List<String> gods = container.select(new TypeLiteral<List<String>>() {}).get();
            gods.clear();
            System.out.println("Adds new gods");
            gods.add("Artemis");
            gods.add("Diana");
            gods.add("Diana");
            gods.add("Poseidon");
            gods.forEach(System.out::println);
            System.out.println("Removing an element");
            gods.remove("Diana");
            gods.forEach(System.out::println);
        }
    }
}

Set

public class Main4 {
    public static void main (String[] args) {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            Set<String> gods = container.select(new TypeLiteral<Set<String>>() {}).get();
            gods.clear();
            System.out.println("Adds new gods");
            gods.add("Artemis");
            gods.add("Diana");
            gods.add("Diana");
            gods.add("Poseidon");
            gods.forEach(System.out::println);
            System.out.println("Removing an element");
            gods.remove("Diana");
            gods.forEach(System.out::println);
        }
    }
}

Queue

public class Main5 {
    public static void main (String[] args) {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            Queue<String> gods = container.select(new TypeLiteral<Queue<String>>() {}).get();
            gods.clear();
            System.out.println("Adds new gods");
            gods.add("Artemis");
            gods.add("Diana");
            gods.add("Poseidon");
            gods.forEach(System.out::println);
            System.out.println("Pool element: " + gods.poll());
            System.out.println("Pool element: " + gods.poll());
            System.out.println("Pool element: " + gods.poll());
            System.out.println("Pool element: " + gods.poll());
            System.out.println("Pool element: " + gods.poll());
            gods.forEach(System.out::println);
        }
    }
}

Map

public class Main6 {
    public static void main(String[] args) {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            Map<String, String> gods = container.select(new TypeLiteral<Map<String, String>>() {
            }).get();
            gods.clear();
            gods.put("hunt", "Artemis");
            gods.put("Sun", "Apollo");
            gods.put("Sea", "Poseidon");
            System.out.println("hunt: " + gods.get("hunt"));
            System.out.println("Sun: " + gods.get("Sun"));
            System.out.println("Sea: " + gods.get("Sea"));
            System.out.println("the keys: " + gods.keySet());
        }
    }
}

Além dessas estruturas similares, o Redis possui outras que não é possível demonstrar através dos padrões Java, que é o caso do SortedSet e o Counter, mas que o framework também abstrai e fornece classes para trabalhar com estas funcionalidades.

SortedSet

public class Main7 {
    public static void main (String[] args) {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            SortedSet gods = container.select(SortedSet.class).get();
            gods.add("Artemis", 10);
            gods.add("Hera", 5);
            gods.add("Zeus", 2);
            gods.add("Apollo", 1);
            System.out.println("The ranking:");
            gods.getRanking().forEach(System.out::println);
            System.out.println("The reverse ranking:");
            gods.getRevRanking().forEach(System.out::println);
            System.out.println("The worse goods: " + gods.range(0, 1));
            System.out.println("The best ones: " + gods.revRange(0, 1));
        }
    }
}

Counter

public class Main8 {
    public static void main (String[] args) {
        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            Counter gods = container.select(Counter.class).get();
            System.out.println("increment: " + gods.increment());
            System.out.println("increment: " + gods.increment(2));
            System.out.println("decrement: " + gods.decrement(2));
        }
    }
}

Como o artigo é focado mais na integração Java com Redis, para aqueles que queiram saber mais especificamente sobre JNoSQL ou Redis, podem acessar os Links Úteis abaixo, além de ter o repositório no GitHub com todos os exemplos utilizados aqui.

Links Úteis