C++ Redis 라이브러리를 사용해본다.
Redis
데이터 베이스 서버에서 쿼리로 조회하는 것보다 캐시 서버(Redis)를 둬 I/O를 동반한 데이터 베이스 서버보다 빠르게 데이터를 가져오기 위해 사용한다.
기본적으로 key-value 쌍의 데이터를 저장한다.
Redis 는 C언어로 작성된 hiredis 라이브러리를 의존하는 C++ 라이브러리를 사용할 예정이다.
C hiredis
https://github.com/redis/hiredis
static 라이브러리를 빌드 한다.
C++ sewnew/redis-plus-plus
https://github.com/sewenew/redis-plus-plus#install-hiredis
redis-plus-plus를 빌드할 때 주의사항
포함 디렉터리
1. #include<hiredis/hiredis.h> // hiredis 헤더를 참조하기 위한 포함할 수 있도록 포함 디렉터리를 추가한다.
2. tls 지원 여부에 따라 no_tls/tls 디렉터리를 포함하도록 한다.
3. cxx11/cxx17 스탠다드에 따라 string_view 같은 지원을 선택할 수 있다.
메인 프로젝트
hiredis 폴더가 존재하는 폴더 경로를 포함 디렉터리에 추가
redis-plus-plus-master/src 폴더 경로를 포함 디렉터리에 추가
- hiredis 정적 라이브러리 링크
- redis++ 정적 라이브러리 링크
- ws_32.lib 윈도우 소켓 라이브러리 링크
헤더 포함
#include <sw/redis++/redis++.h>
using namespace std;
using namespace sw::redis;
기본 key-value에 대한 사용
- get : key에 대응하는 value 가져오기
- set : key에 대응하는 값 설정
- strlen : value 길이 가져오기
- getrange : 부분 길이의 문자열 value 가져오기
- append : 기존 value에 문자열 값 추가
static void example1()
{
redis->set("key", "hello world");
auto val = redis->get("key");
if (val)
{
cout << "val : " << *val << endl;
}
auto len = redis->strlen("key");
if (len)
{
cout << "len : " << len << endl;
}
auto sub_val = redis->getrange("key", 6, -1);
if (!sub_val.empty())
{
cout << "sub val : " << sub_val << endl;
}
redis->append("key", " redis!");
auto val2 = redis->get("key");
if (val2)
{
cout << "val2 : " << *val2 << endl;
}
}
키에 대한 expire 시간 설정 및 정수, 실수 값만큼 증감
static void example2()
{
auto val = redis->get("key");
if (val)
{
cout << "val : " << *val << endl;
}
redis->expire("key", 5s);
this_thread::sleep_for(6s);
val = redis->get("key");
if (!val)
{
cout << "value expired" << endl;
}
redis->set("int", "0");
redis->incr("int");
auto int_val = redis->get("int");
if (int_val)
{
cout << "int val after incr 1 : " << *int_val << endl;
}
redis->incrby("int", 10);
int_val = redis->get("int");
if (int_val)
{
cout << "int val after incr 1 : " << *int_val << endl;
}
}
value가 list 타입으로 사용
deque과 같이 양방향으로 삽입이 가능
- lpush : 왼쪽부터 삽입
- rpush: 오른쪽부터 삽입
- lpop: 왼쪽에서 하나 빼기
- rpop : 오른쪽에서 하나 빼기
- lrange : 인덱스 범위로 list 가져오기
static void example3()
{
vector<string> elements = { "a", "b", "c", "d", "e" };
redis->lpush("my_list", elements.begin(), elements.end());
vector<string> out_elements;
redis->lrange("my_list", 0, -1, back_inserter(out_elements));
cout << "my_list : ";
for (const auto& s : out_elements)
cout << s << ", ";
cout << endl;
redis->rpush("my_list", "apple");
redis->lpop("my_list");
redis->lpop("my_list");
out_elements.clear();
redis->lrange("my_list", 0, -1, back_inserter(out_elements));
cout << "my_list : ";
for (const auto& s : out_elements)
cout << s << ", ";
cout << endl;
}
정렬되지 않은 set
- sadd : 원소 추가
- scard : 원소 개수
- smembers : 모든 원소 가져오기
- sinter : 두 셋의 교차 원소 가져오기
- sismember : 셋에 있는 원소 인 지 판별
// unordered_set
static void example4()
{
redis->sadd("my_unord_set", "ppp");
redis->sadd("my_unord_set", "ccc");
redis->sadd("my_unord_set", "qqq");
int card = redis->scard("my_unord_set"); // 3
cout << "set cardinality : " << card << endl;
vector<string> unord_set;
redis->smembers("my_unord_set", back_inserter(unord_set));
cout << "my_unord_set";
for (auto& p : unord_set)
cout << p << ", ";
cout << endl;
redis->sadd("my_unord_set2", "aaa");
redis->sadd("my_unord_set2", "bbb");
redis->sadd("my_unord_set2", "ccc");
vector<string> unord_set2;
redis->smembers("my_unord_set2", back_inserter(unord_set2));
cout << "my_unord_set2";
for (auto& p : unord_set2)
cout << p << ", ";
cout << endl;
vector<string> inter;
vector<string> li = { "my_unord_set", "my_unord_set2" };
redis->sinter(li.begin(), li.end(), back_inserter(inter));
cout << "intersection : ";
for (auto& p : inter)
cout << p << ", ";
cout << endl;
bool bismem = redis->sismember("my_unord_set2", "ddd");
cout << "ddd is member of my_unord_set2 : " << bismem;
}
정렬된 set
- score 값에 따라 멤버(원소)가 정렬된 형태
- zadd : 멤버와 score 값을 저장
- zrange : 모든 멤버와 score 혹은 멤버만 가져오기
- zscore : 멤버에 해당하는 score 가져오기
static void example5()
{
redis->zadd("my_set", { make_pair("m1", 1.4), make_pair("m2", 2.1), make_pair("m3", -0.3), make_pair("m4", -1.1)});
vector<pair<string, double>> with_scores;
redis->zrange("my_set", 0, -1, back_inserter(with_scores));
cout << endl;
cout << "my_set"<<endl;
for (const auto& p : with_scores)
{
cout << p.first << ": " << p.second << endl;
}
auto d = redis->zscore("my_set", "m2");
if (d)
{
cout << "d score : " << *d << endl;
}
}
value가 맵 인 경우 : hash
- hmset : 모든 해시 맵 멤버 삽입
- hset : 특정 hash key-value 쌍만 멤버로 삽입
- hget : hash key에 해당하는 value 가져옴
- hdel : hash key로 멤버 삭제
- hexists : hash key가 존재하는 지 확인
static void example6()
{
map<string, string> mm = { {"key1", "value1"}, {"key2" ,"value2"}, {"key3", "value3"} };
redis->hmset("my_map", mm.begin(), mm.end());
auto value3 = redis->hget("my_map", "key3");
if (value3)
{
cout << "my_map key3: " << *value3 << endl;
}
redis->hset("my_map", make_pair("key4", "value4"));
bool exists = redis->hexists("my_map", "key4");
cout << "my_map key4 exists : " << exists << endl;
redis->hdel("my_map", "key4");
exists = redis->hexists("my_map", "key4");
cout << "my_map key4 exists after delete : " << exists << endl;
}
'Advanced C++' 카테고리의 다른 글
[Functional C++] 함수형 프로그래밍 (1) 불변성과 순수 함수 (0) | 2022.10.03 |
---|---|
[C++] Protobuf (Google Protocol Buffer) 라이브러리 (0) | 2022.09.27 |
[C++] CryptoPP 암호화/복호화 라이브러리 (0) | 2022.08.11 |
[C++] thread_local 키워드 (0) | 2022.04.26 |
[C++] SEHException : 구조적 예외 처리 Strucutred Exception Handling (0) | 2022.04.20 |