이전 포스팅에서는 간략하게 서버 설정을 진행해보았다.
상세한 서버 설정 항목인 Replication 설정과 Cluster 서비스 설정에 대해서는 추후 따로 포스팅한다.
이번 포스팅에서 캐쉬용도로 사용하는 방식과 No-SQL DB로 CRUD를 처리하는 방법을
간단하게 기술한다.
먼저 사용자 정보를 담는 Dto를 설계한다. Dto를 설계 할 때 Redis에 담겨지는 Object는 반드시 Serializable 인터페이스를 상속 받아야 한다.
직렬화 되지 않은 객체는 Redis에서 반환할 때 원래 객체로 반환 할 수 없다.
public class User implements Serializable{
private String userName;
private String phoneNumber;
private String email;
private String address;
private int userID;
public int getUserID() {
return userID;
}
public void setUserID(int userID) {
this.userID = userID;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
그리고 CRUD 작업을 수행할 간단한 인터페이스를 하나 생성한다.
public interface UserAccessService {
public User getUser(int id);
public void setUser(User user);
public User deleteUser(User User);
public void updateUser(int id, User updateUser);
}
Redis는 기본적으로 Key , Value를 저장하는 데이터 타입에서 자유롭다 개발자의 취향에 따라서 제네릭으로
인터페이스를 구성하는 방법도 가능하다.
public interface UserAccessService {
public User getUser(K key);
public void setUser(V user);
public User deleteUser(V User);
public void updateUser(K key, V updateUser);
}
이 예제에서는 제너릭을 사용하지 않고 진행한다.
UserAccessService를 상속 받는 2개의 클래스를 생성한다.
첫 번째 Dao는 캐쉬를 지원하는 형태로 구성한다.
캐쉬로 Redis를 사용할 때는 Spring 에서 지원하는 기본 Cache Annotation을 숙지해야 한다.
아래의 링크에서 기본 개념과 사용방법을 숙지하자.
http://blog.outsider.ne.kr/1094
@Repository("userDaoCache")
public class UserDaoCache implements UserAccessService {
// 임의의 Database로 가정
private static HashMap<Integer, User> USERMAP = new HashMap<Integer, User>();
/*private HashMap<Integer, User> getUserMap() {
if (userMap == null)
userMap = new HashMap<Integer, User>();
return userMap;
}*/
public UserDaoCache() {
}
@Override
@Cacheable(value = "users", key = "#id")
public User getUser(int id) {
User user = USERMAP.get(id);
System.out.println("This user is come from HashMap : "
+ user.getUserName());
return user;
}
@Override
public void setUser(User user) {
USERMAP.put(user.getUserID(), user);
}
@Override
@CacheEvict(value = "users", allEntries=true)
public User deleteUser(User user) {
USERMAP.remove(user.getUserID());
return null;
}
@Override
@CacheEvict(value = "users", allEntries=true)
public void updateUser(int id, User updateUser) {
USERMAP.replace(id, updateUser);
}
}
두 번째 Dao는 Redis 자체를 no-sql 데이터 저장소로 사용하는 방식이다.
@Repository("userDaoTemplate")
public class UserDaoTemplate implements UserAccessService {
@Autowired
private RedisTemplate<Integer, User> redisTemplate;
public UserDaoTemplate() {
}
@Override
public User getUser(int id) {
User user = redisTemplate.opsForValue().get(id);
return user;
}
@Override
public void setUser(User user) {
redisTemplate.opsForValue().set(user.getUserID(), user);
}
@Override
public User deleteUser(User User) {
redisTemplate.delete(User.getUserID());
return User;
}
@Override
public void updateUser(int id, User updateUser) {
redisTemplate.opsForValue().getAndSet(id, updateUser);
}
}
Redis Template은 Redis에서 지원하는 자료형에 맞게 Ops 함수를 제공한다.
Redis에서 지원하는 자료형 종류를 먼저 확인하자
아래의 링크에서 지원하는 자료형을 확인 할 수 있다. Template 에서는 각 자료형 대로 저장할 수 있도록 오퍼레이터 함수를 지원한다.
http://redis.io/topics/data-types
Redis Crud를 하기 위한 준비가 끝났다.
Cache dao가 동작하는 지 확인하는 Junit 테스트 코드를 설계한다.
@Autowired
@Qualifier("userDaoCache")
private UserAccessService redisCache;
@Test
public void testCache() {
User user = new User();
user.setUserID(1);
user.setUserName("john");
redisCache.setUser(user);
user = redisCache.getUser(1);
System.out.println("Result : " + user.getUserName());
user = redisCache.getUser(1);
System.out.println("Result : " + user.getUserName());
user = redisCache.getUser(1);
System.out.println("Result : " + user.getUserName());
user.setUserName("tommy");
redisCache.updateUser(1, user);
user = redisCache.getUser(1);
System.out.println("Result : " + user.getUserName());
user = redisCache.getUser(1);
System.out.println("Result : " + user.getUserName());
user = redisCache.getUser(1);
System.out.println("Result : " + user.getUserName());
redisCache.deleteUser(user);
}
실행결과는 다음과 같다.
처음 데이터를 읽을 때는 선언한 hashMap 안에 데이터가 출력된다.
이후에 출력되는 데이터는 Cache 에 미리 저장된 데이터가 출력됨을 알 수 있다.
이후에 사용자 정보가 Update 되면 저장된 캐쉬가 초기화 되고 다시 저장된다.
다시 저장된 캐쉬 값이 getuser 함수를 통해서 전달 되는 것을 확인할 수 있다.
두 번째 No-SQL 저장소로 구현된 Dao 가 동작하는 테스트 코드를 설계한다.
@Autowired
@Qualifier("userDaoTemplate")
private UserAccessService redisTemplate;
@Test
public void testRedis()
{
User user = new User();
user.setUserID(1);
user.setUserName("john");
redisTemplate.setUser(user);
User userfromRedis = redisTemplate.getUser(1);
assertThat(user.getUserName(), org.hamcrest.core.Is.is(userfromRedis.getUserName()));
user.setUserName("tommy");
redisTemplate.updateUser(1, user);
userfromRedis = redisTemplate.getUser(1);
assertThat(user.getUserName(), org.hamcrest.core.Is.is(userfromRedis.getUserName()));
redisTemplate.deleteUser(user);
userfromRedis = redisTemplate.getUser(1);
}
수행의 결과를 확인해보자. 설정에 문제가 없을 경우 정상적으로 Junit 테스트가 실행될 것이다.
Dao 코드를 구성하기 전에 redis cli를 이용하여 구성하려는 Dao가 정상적으로 동작하는 지 확인해보는 것이 좋다.
소스 코드 위치
https://github.com/wargen99/wargen-repo.git
다음 포스팅에서는 Spring session과 Redis를 이용하여 분산환경에서 일관된 세션 유지 방법에 대해 포스팅한다.