Redis - ttulka/technologies GitHub Wiki

Redis is in the family of databases called key-value stores.

Basics

Create, read, test, and delete the value:

SET server:name "tux1"

GET server:name

EXISTS server:name

DEL server:name

Increment and decrement the value:

INCR counter
INCRBY counter 100

DECR counter
DECRBY counter 100

All the Redis operations implemented by single commands are atomic.

A key can be set to expire with EXPIRE command, TTL command tests how long a key will exist:

SET resource:lock "Demo"
EXPIRE resource:lock 120

TTL resource:lock

The -2 for the TTL of the key means that the key does not exist (anymore). A -1 for the TTL of the key means that it will never expire.

Expiration will be reset when SET again. Atomically:

SET resource:lock "Demo" EX 120

It is also possible to cancel the time to live of a key removing the expire and making the key permanent again:

PERSIST resource:lock
TTL resource:lock

Complex Data Structures

Redis also supports several more complex data structures.

Lists

A list is a series of ordered values.

RPUSH puts the new element at the end of the list:

RPUSH friends "Alice"
RPUSH friends "Bob"

LPUSH puts the new element at the start of the list:

LPUSH friends "Joe"

LRANGE gives a subset of the list. A value of -1 for the second parameter means to retrieve elements until the end of the list, -2 means to include up to the penultimate, and so forth:

LRANGE friends 0 -1 	=> 1) "Joe", 2) "Alice", 3) "Bob"
LRANGE friends 0 1 		=> 1) "Joe", 2) "Alice"
LRANGE friends 1 2 		=> 1) "Alice", 2) "Bob"

LPOP removes the first element from the list and returns it:

LPOP friends 		=> "Sam"

RPOP removes the last element from the list and returns it:

RPOP friends 		=> "Bob"

The list now only has one element:

LLEN friends 			=> 1
LRANGE friends 0 -1 	=> 1) "Alice"

Both RPUSH and LPUSH commands are variadic, so you can specify multiple elements in the same command execution:

RPUSH friends 1 2 3 	=> 4

Sets

A set does not have a specific order and each element may only appear once.

SADD adds the given member to the set, again this command is also variadic:

SADD superpowers "flight" "reflexes"

The return value of SADD returns 0 if the element we try to add is already inside, otherwise 1 is returned:

SADD superpowers "flight" 			=> 0
SADD superpowers "invisibility" 	=> 1

SREM removes the given member from the set, returning 1 or 0 to signal if the member was actually there or not:

SREM superpowers "flight" 			=> 1
SREM superpowers "making pizza" 	=> 0

SISMEMBER tests if the given value is in the set. It returns 1 if the value is there and 0 if it is not:

SISMEMBER superpowers "flight" 			=> 1
SISMEMBER superpowers "invisibility" 	=> 0

SMEMBERS returns a list of all the members of this set:

SMEMBERS superpowers 		=> 1) "flight", 2) "invisibility"

SUNION combines two or more sets and returns the list of all elements:

SADD birdpowers "pecking"
SADD birdpowers "flight"
SUNION superpowers birdpowers 		=> 1) "pecking", 2) "invisibility", 3) "flight"

Sorted Sets

A sorted set is similar to a regular set, but now each value has an associated score.

ZADD hackers 1940 "Alan Kay"
ZADD hackers 1969 "Linus Torvalds"
ZADD hackers 1912 "Alan Turing"

Hashes

Hashes are maps between string fields and string values, so they are the perfect data type to represent objects:

HSET user:1000 name "John Smith"
HSET user:1000 email "[email protected]"
HSET user:1000 password "s3cret"

You can also set multiple fields at once:

HMSET user:1001 name "Mary Jones" password "hidden" email "[email protected]"

Use HGETALL to get back the saved data:

HGETALL user:1000

HGET user:1001 name 	=> "Mary Jones"

Numerical values in hash fields are handled exactly the same as in simple strings and there are operations to increment this value in an atomic way:

HSET user:1000 visits 10
HINCRBY user:1000 visits 1 		=> 11
HINCRBY user:1000 visits 10 	=> 21
HDEL user:1000 visits
HINCRBY user:1000 visits 1 		=> 1

Jedis

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>...</version>
</dependency>
JedisPool pool = new JedisPool(new JedisPoolConfig(), "localhost");

/// Jedis implements Closeable. Hence, the jedis instance will be auto-closed after the last statement.
try (Jedis jedis = pool.getResource()) {
  /// ... do stuff here ... for example
  jedis.set("foo", "bar");
  String foobar = jedis.get("foo");
  jedis.zadd("sose", 0, "car"); jedis.zadd("sose", 0, "bike"); 
  Set<String> sose = jedis.zrange("sose", 0, -1);
}
/// ... when closing your application:
pool.close();

Strings

jedis.set("events/city/rome", "32,15,223,828");
String cachedResponse = jedis.get("events/city/rome");

Lists

jedis.lpush("queue#tasks", "firstTask");
jedis.lpush("queue#tasks", "secondTask");
 
String task = jedis.rpop("queue#tasks");

Sets

jedis.sadd("nicknames", "nickname#1");
jedis.sadd("nicknames", "nickname#2");
jedis.sadd("nicknames", "nickname#1");
 
Set<String> nicknames = jedis.smembers("nicknames");
boolean exists = jedis.sismember("nicknames", "nickname#1");

Hashes

jedis.hset("user#1", "name", "Peter");
jedis.hset("user#1", "job", "politician");
		
String name = jedis.hget("user#1", "name");
		
Map<String, String> fields = jedis.hgetAll("user#1");
String job = fields.get("job");

Sorted Sets

Map<String, Double> scores = new HashMap<>();
 
scores.put("PlayerOne", 3000.0);
scores.put("PlayerTwo", 1500.0);
scores.put("PlayerThree", 8200.0);
 
scores.entrySet().forEach(playerScore -> {
    jedis.zadd(key, playerScore.getValue(), playerScore.getKey());
});
		
String player = jedis.zrevrange("ranking", 0, 1).iterator().next();
long rank = jedis.zrevrank("ranking", "PlayerOne");

Transactions

String friendsPrefix = "friends#";
String userOneId = "4352523";
String userTwoId = "5552321";
 
Transaction t = jedis.multi();
t.sadd(friendsPrefix + userOneId, userTwoId);
t.sadd(friendsPrefix + userTwoId, userOneId);
t.exec();

Pipelining

String userOneId = "4352523";
String userTwoId = "4849888";
 
Pipeline p = jedis.pipelined();
p.sadd("searched#" + userOneId, "paris");
p.zadd("ranking", 126, userOneId);
p.zadd("ranking", 325, userTwoId);
Response<Boolean> pipeExists = p.sismember("searched#" + userOneId, "paris");
Response<Set<String>> pipeRanking = p.zrange("ranking", 0, -1);
p.sync();
 
String exists = pipeExists.get();
Set<String> ranking = pipeRanking.get();

Publish/Subscribe

Subscriber

Jedis jSubscriber = new Jedis();
jSubscriber.subscribe(new JedisPubSub() {
    @Override
    public void onMessage(String channel, String message) {
        // handle message
    }
}, "channel");

Publisher

Jedis jPublisher = new Jedis();
jPublisher.publish("channel", "test message");

References

⚠️ **GitHub.com Fallback** ⚠️