Skip to content
Low level Redis client (but you won't need more than this)
Java Shell
Branch: master
Clone or download
Latest commit 6657f1a Jun 25, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
src/nl/melp/redis add use case for subscription on key events Jun 25, 2019
test/nl/melp/redis add use case for subscription on key events Jun 25, 2019
.gitignore ignore /bin Feb 19, 2019
LICENSE Initial commit Jan 18, 2019 fix doc issue Jun 25, 2019 make jar runnable to run tests Mar 14, 2019 make jar runnable to run tests Mar 14, 2019


Low level Redis client (but you really won't need anything more than this!)


Either package the library using ./ or whatever package manager you fancy, or just copy it into your source tree.

Then create a socket connection and start speaking Redis.

nl.melp.redis.Redis r = new nl.melp.redis.Redis(new Socket("", 6379));"SET", "foo", "123");"INCRBY", "foo", "456");
System.out.println("GET", "foo")); // will print '579'

How data is parsed

  • Error responses are translated to an Exception (nl.melp.redis.Redis.Parser.ServerError)
  • Strings become byte[]
  • Numbers become Long
  • Arrays become List, where the entry can be any of String, Long or List<Object>.

    Since call uses a template return value, return type is statically inferred:"LPUSH", "mylist", "A", "B", "C", "D");
    List<Object> l ="LRANGE", "mylist", "0", "200");
    System.out.println("Size: " + l.size()); // prints "Size: 4"
    System.out.println((String)l.get(0)); // prints "A"

    You will have to do some casting yourself in case of List responses. The reasoning here is that you know what data to expect so you're responsible for applying the correct casts in the correct context.

    Refer to the Redis documentation for the return types of all calls and nl.melp.redis.RedisTest for some working examples.


    The idea of pipelining is that you can keep writing commands without having read the response. This is an inherent feature of the protocol. The call() method by default returns the response immediately, but if you wish to keep sending commands without reading the response, you can use the pipeline() call. This is typically useful for a MULTI/EXEC call where the responses aren't directly useful.

        .call("INCR", "A")
        .call("INCR", "A")
        .call("INCR", "A")
        .call("INCR", "A")

    This will result in a List<Object> containing a list for each of the responses.

    Is the connection thread safe?

    No. You need to make sure that the connection is accessed atomically. However, there is a method which you can use to do some simple redis operations in isolation. It creates a connection and closes it directly after: ->"INCR", "mycounter"));

    How should I manage my connections?

    However you wish. This library is a protocol implementation only. Managing a connection pool is not at all Redis-specific, so it doesn't belong here.

    Having said that, this mostly depends on your use case. Typically if you have a webserver with 20 threads, you can have a socket per thread managed somewhere (e.g. ThreadLocal) and if you run a threadpool with 20 workers you can have one socket per thread there as well. This keeps things simple and practical to reason about and you don't have to worry who needs to create the socket at what point in time. You do need some error handling which, in case of managing the sockets centrally is a tiny bit easier. On the other hand, if you expect to be creating a lot of threads and not a lot of these threads need the connection, you probably want to implement a pool.

    Summarizing, this is a trade-off which you can decide on for your own. Generally speaking: don't overcomplicate stuff without good reason.

    In terms of performance: creating socket connections on-the-fly is comparable to reusing connections. See the performance tests inside RedisTest for more information.

    Questions? Issues?

    Feel free to report issues here.

You can’t perform that action at this time.