How to Use the Redis SET Command in Java with Redisson
Published on July 17, 2026
SET is the most fundamental write in Redis. It stores a string value under a key, and almost everything else you do with Redis strings builds on it. But the modern SET command is far more capable than "put a value in a key" — it can attach an expiration, write conditionally, and return the previous value, all in a single atomic step. It has also quietly absorbed several older commands that you'll still see in tutorials and legacy code.
This guide covers the SET command and its whole string-command family — GET, the EX/NX/XX/GET options, the deprecated SETEX/SETNX, and the bulk commands MSET and MGET — and shows how to use each one from Java with Redisson, a high-level Valkey and Redis client. One quick note before we start: this is about the SET command, which writes a single string. It's unrelated to the Redis Set data type, an unordered collection of unique members — despite the shared name.
The examples assume you already have a RedissonClient. If you don't, How to Use Redis in Java walks through the dependency and connection setup in a few minutes.
The SET and GET Basics
At its simplest, SET writes a value and GET reads it back:
SET user:1001:name "Ada"
GET user:1001:name
# "Ada"
A few properties are worth knowing. SET overwrites unconditionally — if the key already holds a value, of any type, it's replaced, and any existing time-to-live is cleared unless you say otherwise. Values are binary-safe strings, so a "string" can be text, a number, JSON, or serialized binary such as an image, up to a maximum of 512 MB per value.
The Extended SET Options
Since Redis 2.6.12, SET accepts a set of options that fold behavior which used to require multiple commands into one atomic call:
| Option | Effect |
|---|---|
EX seconds / PX milliseconds | Set the value and a time-to-live together. |
EXAT / PXAT | Expire at an absolute Unix timestamp (seconds / milliseconds). |
NX | Only set the key if it does not already exist. |
XX | Only set the key if it does already exist. |
GET | Return the key's old value (or nil) instead of OK. |
KEEPTTL | Keep the existing TTL instead of clearing it. |
The core EX, PX, NX, and XX options date back to 2.6.12; KEEPTTL arrived in Redis 6.0, and GET, EXAT, and PXAT in 6.2. On any recent Redis or Valkey server, all of them are available.
So a cache entry that should expire after five minutes is one command:
SET session:abc "{...}" EX 300
And a conditional write — "create this key only if nobody else has" — is another:
SET lock:job:42 "worker-1" NX EX 30
# OK → the key was created
# (nil) → the key already existed, nothing changed
SET normally replies OK. With NX or XX, it returns nil when the condition isn't met, and with GET it returns the previous value.
The Legacy Commands SET Replaced
Before those options existed, Redis had separate commands for each behavior. You'll still encounter them, but they're no longer the recommended way to write new code:
-
SETEX key seconds valueandPSETEX key ms value— replaced bySET ... EX/PX. -
SETNX key value— replaced bySET ... NX. See Redis SETNX for why the older command is a common source of buggy locks. -
GETSET key value— replaced bySET ... GET.
SETEX, SETNX, and PSETEX have been deprecated since 2.6.12, and GETSET since 6.2. The single-command SET form is preferred because it's atomic: with the old SETNX + EXPIRE pattern, a crash between the two commands leaves a key with no expiration, which is exactly the kind of subtle deadlock that SET key value NX EX 30 avoids.
Setting and Getting Multiple Keys: MSET and MGET
When you're moving several values at once, round-tripping one SET per key is wasteful. MSET and MGET batch the work into a single command:
MSET user:1:name "Ada" user:2:name "Linus" user:3:name "Grace"
MGET user:1:name user:2:name user:3:name
# 1) "Ada"
# 2) "Linus"
# 3) "Grace"
MSET is atomic — all keys are set together, and no client ever sees a half-applied state. MGET returns values in request order, with nil for any key that doesn't exist. There's also MSETNX, which sets every pair only if none of the keys already exist (all-or-nothing); unlike SETNX, it isn't deprecated, because no single SET-based command reproduces its multi-key semantics.
The one real limitation: MSET can't attach a TTL. There's no MSET ... EX form, so if you need multiple keys that each expire, plain commands force you to choose between an atomic write without expirations or per-key SET ... EX calls that aren't atomic together. We'll solve that cleanly in Java below.
The Redis SET Command in Java with Redisson
Rather than send raw commands, Redisson gives you the Redis string as a typed Java object called an RBucket. An RBucket<V> is a holder for a single value, and its methods map directly onto the SET command family:
| Redis command | Redisson RBucket method |
|---|---|
SET key value | bucket.set(value) |
SET key value EX 10 (SETEX) | bucket.set(value, 10, TimeUnit.SECONDS) |
GET key | bucket.get() |
SET key value NX (SETNX) | bucket.setIfAbsent(value) |
SET key value XX | bucket.setIfExists(value) |
SET key value GET (GETSET) | bucket.getAndSet(value) |
GETDEL key | bucket.getAndDelete() |
STRLEN key | bucket.size() |
In practice that looks like ordinary Java:
import org.redisson.api.RBucket;
import java.util.concurrent.TimeUnit;
RBucket<String> bucket = redisson.getBucket("user:1001:name");
// SET
bucket.set("Ada");
// GET
String name = bucket.get(); // "Ada"
// SET ... EX 300 (value plus a 5-minute TTL)
bucket.set("Ada", 300, TimeUnit.SECONDS);
// SET ... NX → true if the key was absent and is now set
boolean created = bucket.setIfAbsent("Ada");
// SET ... XX → true only if the key already existed
boolean updated = bucket.setIfExists("Grace");
// SET ... GET → returns the previous value
String previous = bucket.getAndSet("Linus");
Because Redisson serializes values through a configurable codec, the V in RBucket<V> doesn't have to be a String — you can store any object and let Redisson handle serialization to and from the binary value Redis actually stores. There's also compareAndSet(expected, update) for lock-free conditional updates, which has no single-command Redis equivalent — Redisson implements it with a server-side script.
Bulk String Operations in Java: RBuckets and RBatch
For the multi-key commands, Redisson exposes an RBuckets view that maps onto MGET, MSET, and MSETNX:
import org.redisson.api.RBuckets;
import java.util.Map;
RBuckets buckets = redisson.getBuckets();
// MGET → returns a Map of the keys that exist
Map<String, String> loaded =
buckets.get("user:1:name", "user:2:name", "user:3:name");
// MSET → write several keys at once
Map<String, String> toWrite = Map.of(
"user:1:name", "Ada",
"user:2:name", "Linus");
buckets.set(toWrite);
// MSETNX → set all of them only if none already exist
boolean allSet = buckets.trySet(toWrite);
And here's the answer to the MSET-can't-set-a-TTL problem. Use an RBatch to pipeline any number of individual set(value, ttl) calls, each with its own expiration, and send them to the server in a single round trip:
import org.redisson.api.RBatch;
import java.util.concurrent.TimeUnit;
RBatch batch = redisson.createBatch();
batch.getBucket("session:a").setAsync("{...}", 300, TimeUnit.SECONDS);
batch.getBucket("session:b").setAsync("{...}", 600, TimeUnit.SECONDS);
batch.getBucket("session:c").setAsync("{...}", 900, TimeUnit.SECONDS);
batch.execute();
You get the network efficiency of a bulk write and per-key TTLs — something no single native Redis command offers.
Beyond Plain Strings
Once values are Java objects rather than hand-encoded strings, the RBucket becomes a natural fit for more than raw storage. It's the simplest building block for caching a single computed value with an expiration, and every method shown here also has asynchronous, reactive, and RxJava variants (RBucketAsync, RBucketReactive, RBucketRx) so you can match it to whatever concurrency model your service uses. For the bigger picture of how each Redis type maps to a Java object, see Redis Data Structures in Java.
Frequently Asked Questions
Is SETNX Deprecated?
Yes. SETNX has been deprecated since Redis 2.6.12 in favor of SET key value NX, which does the same thing and can set an expiration atomically in the same command. See Redis SETNX for the details and the locking pitfalls it causes.
How Do I Set a Redis Key With an Expiration?
Use the EX (seconds) or PX (milliseconds) option: SET key value EX 60. In Redisson, pass the TTL to set: bucket.set(value, 60, TimeUnit.SECONDS).
What Is the Difference Between SET NX and SETNX?
They perform the same "set only if the key is absent" check. SETNX is the older standalone command and returns 1 or 0; SET ... NX is the modern option, returns OK or nil, and can be combined with EX to set a TTL in the same atomic call. New code should prefer SET ... NX.
Can MSET Set a TTL on the Keys?
No. MSET has no expiration option. To write multiple keys that each expire, pipeline individual SET ... EX calls — in Redisson, use an RBatch of setAsync(value, ttl, unit) calls, which run in one round trip while keeping per-key TTLs.
What Is the Redisson Equivalent of the Redis SET Command?
The RBucket object. bucket.set(value) maps to SET, bucket.get() to GET, bucket.setIfAbsent(value) to SET ... NX, bucket.setIfExists(value) to SET ... XX, and bucket.getAndSet(value) to SET ... GET. Multiple keys are handled by RBuckets.
Next Steps
You now have the full SET command family and its Java equivalents. From here, a few natural directions: read Redis SETNX and How to Use Redis Locks in Java if you reached for SET ... NX to build a lock, explore How to Use Redis Cache in Java to turn an RBucket into a proper cache entry, or browse the Redisson documentation for the async and reactive APIs. For local caching, data partitioning, and advanced cache strategies on top of the same API, Redisson PRO adds them — you can try it for free.