[Java] Redis 데이터베이스를 접속해서 사용하는 방법(Jedis 라이브러리)


Development note/Java  2022. 2. 16. 18:12

안녕하세요. 명월입니다.


이 글은 Java에서 Redis 데이터베이스를 접속해서 사용하는 방법(Jedis 라이브러리)에 대한 글입니다.


Redis 데이터베이스는 RDB 종류가 아닌 NoSQL 종류의 Key-Value타입의 데이터베이스입니다. 간단하게 공유 메모리 데이터베이스입니다.

이전 글에서 Linux 환경에서 설치 및 사용하는 방법에 대해 설명한 적 있습니다.

링크 - [CentOS] Redis 데이터베이스 설치와 명령어 사용법


그럼 Redis 데이터베이스를 Java에서 사용해 보겠습니다.

Java에서 Redis 데이터베이스를 사용하기 위해서는 Maven을 통해서 Jedis 라이브러리를 설치해야 합니다.

<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.1.1</version>
</dependency>

리포지토리 - https://mvnrepository.com/artifact/redis.clients/jedis/4.1.1

먼저 기본적으로 Redis 데이터베이스에 값을 저장하고 취득하는 코드를 작성하겠습니다.

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Protocol;

public class Program {
  // 실행 함수
  public static void main(String... args) {
    // redis 접속한다.
    try (var pool = new JedisPool("192.168.1.200", Protocol.DEFAULT_PORT)) {
      // Resource 취득한다. (사실 이게 Pool에서 접속을 하는지 Resource 취득할 때 접속을 하는지 명확한 설명이 없음)
      try (var jedis = pool.getResource()) {
        // test 키로 hello world 값을 넣는다.
        jedis.set("test", "hello world");
        // test1 키로 hello world expire 값을 넣는다. (만료시간 60초)
        jedis.setex("test1", 60, "hello world expire");

        // test 키로 값을 취득한다.
        var data = jedis.get("test");
        // 콘솔 출력
        System.out.println(data);
        // test1 키로 값을 취득
        data = jedis.get("test1");
        // 콘솔 출력
        System.out.println(data);
      }
    }
  }
}

위 소스에서는 test 키로 hello world 값을 넣었습니다. 그리고 test1로 만료시간 60초인 hello world expire 값을 넣었습니다.

그리고 test와 test1의 키로 데이터를 취득하니 위에서 넣은 hello world 값이 나옵니다.


관련 함수에 관해서는 API 도큐멘트를 참조하세요.

링크 - https://javadoc.io/doc/redis.clients/jedis/latest/index.html


위 소스는 단순하게 key 값을 이용해서 데이터를 입력하고 취득하는 처리입니다.

실전에서 사용할 만한 코드를 작성해 보겠습니다.

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Protocol;

// Node 클래스
class Node implements Serializable {
  // Serializable 인터페이스를 상속받으면 serialVersionUID를 설정해야 한다.
  private static final long serialVersionUID = 1L;
  // 맴버 변수
  private String data;
  // 맴버 변수 setter 
  public void setData(String data) {
    // 맴버 변수 설정
    this.data = data;
  }
  // 출력 함수
  public void print() {
    // 콘솔 출력
    System.out.println("data = " + data);
  }
}

public class Program {
  // Node 클래스를 직렬화하여 byte타입으로 변환
  static byte[] convertToStringFromClass(Node node) {
    // 직렬화
    try (var baos = new ByteArrayOutputStream()) {
      try (var oos = new ObjectOutputStream(baos)) {
        // 변환
        oos.writeObject(node);
        // Node클래스를 byte 배열로 변환
        return baos.toByteArray();
      }
    } catch (Throwable e) {
      throw new RuntimeException(e);
    }
  }

  // 실행 함수
  public static void main(String... args) {
    // redis 접속한다.
    try (var pool = new JedisPool("192.168.1.200", Protocol.DEFAULT_PORT)) {
      // Resource 취득한다. (사실 이게 Pool에서 접속을 하는지 Resource 취득할 때 접속을 하는지 명확한 설명이 없음)
      try (var jedis = pool.getResource()) {
        // 인스턴스 생성
        var node = new Node();
        // 데이터 설정
        node.setData("Hello world");
        
        // Redis 데이터베이스에 node 키로 설정
        jedis.set("node".getBytes(), convertToStringFromClass(node));
      }
    }
  }
}

Node 클래스를 인스턴스 생성해서 직렬화로 byte 타입으로 변환했습니다. 그리고 byte 타입으로 변환한 값을 Redis 데이터베이스에 입력했습니다.

다시 이걸 취득해 보겠습니다.

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Protocol;

// Node 클래스
class Node implements Serializable {
  // Serializable 인터페이스를 상속받으면 serialVersionUID를 설정해야 한다.
  private static final long serialVersionUID = 1L;
  // 맴버 변수
  private String data;
  // 맴버 변수 setter
  public void setData(String data) {
    // 맴버 변수 설정
    this.data = data;
  }
  // 출력 함수
  public void print() {
    // 콘솔 출력
    System.out.println("data = " + data);
  }
}

public class Program {
  // 데이터를 역직렬화 해서 Node 클래스로 변환
  static Node convertToClassFromString(byte[] binary) {
    // 역직렬화
    try (var bais = new ByteArrayInputStream(binary)) {
      try (var ois = new ObjectInputStream(bais)) {
        // byte 배열의 데이터를 Node의 클래스로 변환한다.
        return (Node) ois.readObject();
      }
    } catch (Throwable e) {
      throw new RuntimeException(e);
    }
  }

  // 실행 함수
  public static void main(String... args) {
    // redis 접속한다.
    try (var pool = new JedisPool("192.168.1.200", Protocol.DEFAULT_PORT)) {
      // Resource 취득한다. (사실 이게 Pool에서 접속을 하는지 Resource 취득할 때 접속을 하는지 명확한 설명이 없음)
      try (var jedis = pool.getResource()) {
        // Redis 데이터베이스에 node 키로 취득
        var binary = jedis.get("node".getBytes());
        // byte 타입을 node 클래스로 변환
        var node = convertToClassFromString(binary);
        // print 함수 실행
        node.print();
      }
    }
  }
}

Redis 데이터베이스에서 node 키로 되어 있는 byte 값을 취득하고 역직렬화를 통해 Node 클래스로 변환합니다.

print 함수를 호출하면 위에서 입력한 Hello world 값이 출력되었습니다.


직렬화를 사용하면 같은 Java 프로그램에서는 문제 없겠지만 다른 언어의 프로그램에서는 사용할 수 없습니다. 그래서 Json 타입으로 변환해서 사용합니다.

import java.io.Serializable;
import com.google.gson.Gson;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Protocol;

// Node 클래스
class Node implements Serializable {
  // Serializable 인터페이스를 상속받으면 serialVersionUID를 설정해야 한다.
  private static final long serialVersionUID = 1L;
  // 맴버 변수
  private String data;
  // 맴버 변수 setter
  public void setData(String data) {
    // 맴버 변수 설정
    this.data = data;
  }
  // 출력 함수
  public void print() {
    // 콘솔 출력
    System.out.println("data = " + data);
  }
}

public class Program {
  // 실행 함수
  public static void main(String... args) {
    Gson gson = new Gson();
    // redis 접속한다.
    try (var pool = new JedisPool("192.168.1.200", Protocol.DEFAULT_PORT)) {
      // Resource 취득한다. (사실 이게 Pool에서 접속을 하는지 Resource 취득할 때 접속을 하는지 명확한 설명이 없음)
      try (var jedis = pool.getResource()) {
        // 인스턴스 생성
        var node = new Node();
        // 데이터 설정
        node.setData("Hello world");
        // node 인스턴스를 json 타입의 string으로 변환
        var json = gson.toJson(node);
        // Redis 데이터베이스에 node 키로 설정
        jedis.set("node", json);
      }
    }
  }
}

Node 인스턴스를 Gson클래스로 사용해서 Json 타입의 String 데이터로 변환했습니다. 그대로 String 데이터를 Redis로 입력했습니다.

import java.io.Serializable;
import com.google.gson.Gson;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Protocol;

// Node 클래스
class Node implements Serializable {
  // Serializable 인터페이스를 상속받으면 serialVersionUID를 설정해야 한다.
  private static final long serialVersionUID = 1L;
  // 맴버 변수
  private String data;

  // 맴버 변수 setter
  public void setData(String data) {
    // 맴버 변수 설정
    this.data = data;
  }

  // 출력 함수
  public void print() {
    // 콘솔 출력
    System.out.println("data = " + data);
  }
}

public class Program {
  // 실행 함수
  public static void main(String... args) {
    Gson gson = new Gson();
    // redis 접속한다.
    try (var pool = new JedisPool("192.168.1.200", Protocol.DEFAULT_PORT)) {
      // Resource 취득한다. (사실 이게 Pool에서 접속을 하는지 Resource 취득할 때 접속을 하는지 명확한 설명이 없음)
      try (var jedis = pool.getResource()) {
        // Redis 데이터베이스에서 node 키로 데이터 취득
        var data = jedis.get("node");
        // json 타입의 데이터를 node로 변환
        var node = gson.fromJson(data, Node.class);
        // print 함수 실행
        node.print();
      }
    }
  }
}

Redis 데이터베이스에 node키로 json 타입의 string 데이터를 취득합니다.

그리고 데이터를 Gson 클래스를 이용해서 Node 클래스로 변환합니다. 그리고 print 함수를 호출하니 위에 입력한 Hello world 값이 출력되었습니다.


다음은 Redis에서 사용될 List와 Map, SortedSet 형식의 자료형입니다.

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Protocol;

public class Program {
  // 실행 함수
  public static void main(String... args) {
    // redis 접속한다.
    try (var pool = new JedisPool("192.168.1.200", Protocol.DEFAULT_PORT)) {
      // Resource 취득한다. (사실 이게 Pool에서 접속을 하는지 Resource 취득할 때 접속을 하는지 명확한 설명이 없음)
      try (var jedis = pool.getResource()) {
        // List 형식 오른쪽 Push
        jedis.rpush("list", "1");
        // List 형식 왼쪽 Push
        jedis.lpush("list", "2");
        // 2, 1
        // 콘솔 출력
        System.out.println(jedis.lpop("list"));
        System.out.println(jedis.lpop("list"));
        // 개행
        System.out.println();

        // Hash 형식의 key-value 값 입력
        jedis.hset("map", "a", "1");
        jedis.hset("map", "b", "2");
        jedis.hset("map", "c", "3");

        // 개행
        System.out.println(jedis.hget("map", "b"));
        // 개행
        System.out.println();
        // SortedSet 형식의 값 입력
        jedis.zadd("SortedSet", 1, "aaa");
        jedis.zadd("SortedSet", 0, "bbb");
        // sort 되어 출력
        for (var sort : jedis.zscan("SortedSet", "").getResult()) {
          // 콘솔 출력
          System.out.println(sort.getElement());
        }
      }
    }
  }
}

위는 Redis에서 list와 map, SortedSet 형식으로 사용되는 타입입니다.


사실 저는 잘 사용하지 않는 타입이기도 합니다.

Redis 프로그램의 알고리즘이 나쁘다고는 생각하지는 않지만 Redis 데이터베이스의 성능에 대한 병목 현상이나 알고리즘의 성능이 C#의 기본 List나 Dictionary보다 더 좋다고 생각되지는 않아서 가능하면 데이터를 그대로 넣고 취득해서 프로그램 내부에서 처리합니다.

제가 아직 Redis의 경험이 많지 않아서 정확하게는 잘 모르겠네요.


여기까지 Java에서 Redis 데이터베이스를 접속해서 사용하는 방법에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.