修改本页
Redis

SETNX key value

Set key to hold string value if key does not exist. In that case, it is equal to SET. When key already holds a value, no operation is performed. SETNX is short for "SET if N ot e X ists".

返回值

Integer reply, specifically:

例子

redis>  SETNX mykey "Hello"
(integer) 1
redis>  SETNX mykey "World"
(integer) 0
redis>  GET mykey
"Hello"
redis> 

Design pattern: Locking with SETNX

NOTE: Starting with Redis 2.6.12 it is possible to create a much simpler locking primitive using the SET command to acquire the lock, and a simple Lua script to release the lock. The pattern is documented in the SET command page.

The old SETNX based pattern is documented below for historical reasons.

SETNX can be used as a locking primitive. For example, to acquire the lock of the key foo, the client could try the following:

SETNX lock.foo <current Unix time + lock timeout + 1>

If SETNX returns 1 the client acquired the lock, setting the lock.foo key to the Unix time at which the lock should no longer be considered valid. The client will later use DEL lock.foo in order to release the lock.

If SETNX returns 0 the key is already locked by some other client. We can either return to the caller if it's a non blocking lock, or enter a loop retrying to hold the lock until we succeed or some kind of timeout expires.

Handling deadlocks

In the above locking algorithm there is a problem: what happens if a client fails, crashes, or is otherwise not able to release the lock? It's possible to detect this condition because the lock key contains a UNIX timestamp. If such a timestamp is equal to the current Unix time the lock is no longer valid.

When this happens we can't just call DEL against the key to remove the lock and then try to issue a SETNX, as there is a race condition here, when multiple clients detected an expired lock and are trying to release it.

Fortunately, it's possible to avoid this issue using the following algorithm. Let's see how C4, our sane client, uses the good algorithm:

Important note: In order to make this locking algorithm more robust, a client holding a lock should always check the timeout didn't expire before unlocking the key with DEL because client failures can be complex, not just crashing but also blocking a lot of time against some operations and trying to issue DEL after a lot of time (when the LOCK is already held by another client).

Comments powered by Disqus