Non è possibile, poiché tutti i comandi (incluso get) vengono effettivamente eseguiti in fase di esecuzione. In questa situazione, il comando get restituisce solo un oggetto futuro, non il valore effettivo.
Esistono due modi per implementare tale transazione.
Utilizzo di una clausola WATCH
La clausola di controllo viene utilizzata per la protezione dagli aggiornamenti simultanei. Se il valore della variabile viene aggiornato tra la clausola watch e multi, i comandi nel blocco multi non vengono applicati. Spetta al cliente tentare la transazione un'altra volta.
loop do
$redis.watch "foo"
val = $redis.get("foo")
if val == "bar" then
res = $redis.multi do |r|
r.set("foo", "baz")
end
break if res
else
$redis.unwatch "foo"
break
end
end
Qui lo script è un po' complesso perché il contenuto del blocco può essere vuoto, quindi non c'è un modo semplice per sapere se la transazione è stata annullata o se non è avvenuta affatto. In genere è più facile quando i risultati del multiblocco restituiscono in tutti i casi tranne se la transazione viene annullata.
Utilizzo degli script Lua lato server
Con Redis 2.6 o superiore, gli script Lua possono essere eseguiti sul server. L'esecuzione dell'intero script è atomica. Può essere facilmente implementato in Ruby:
cmd = <<EOF
if redis.call('get',KEYS[1]) == ARGV[1] then
redis.call('set',KEYS[1],ARGV[2] )
end
EOF
$redis.eval cmd, 1, "foo", "bar", "baz"
Questo è in genere molto più semplice rispetto all'utilizzo delle clausole WATCH.