TL; DR: отсутствует надлежащая поддержка транзакций Redis с использованием Reactive API
Причина заключается в модели выполнения: как Redis выполняет транзакции и как должен работать реактивный API.
При использовании транзакций соединение переходит в состояние транзакции, затем команды ставятся в очередь и, наконец, выполняются с EXEC
.Выполнение команд в очереди с помощью exec делает условием выполнения отдельных команд команду EXEC
.
Рассмотрим следующий фрагмент (код салата):
RedisReactiveCommands<String, String> commands = …;
commands.multi().then(commands.set("key", "value")).then(commands.exec());
Эта последовательность показывает вызов команды внесколько линейный способ:
- Выпуск
MULTI
- После завершения
MULTI
введите команду SET
- После завершения
SET
, вызовите EXEC
Предупреждение о том, что SET
: SET
завершается только после вызова EXEC
.Таким образом, это означает, что у нас есть прямая ссылка на команду exec.Мы не можем прослушать команду, которая будет выполнена в будущем.
Вы можете применить обходной путь:
RedisReactiveCommands<String, String> commands = …
Mono<TransactionResult> tx = commands.multi()
.flatMap(ignore -> {
commands.set("key", "value").doOnNext(…).subscribe();
return commands.exec();
});
Обходной путь будет включать подписку команд в вашем коде (Внимание: этоявляется анти-паттерном в реактивном программировании).После вызова exec()
вы получите TransactionResult
взамен.
Обратите внимание: хотя вы можете получить результаты с помощью Mono<TransactionResult>
, фактическая команда SET
также выдает свой результат (см. doOnNext(…)
).
Это, как говорится, позволяет нам вернуться к актуальному вопросу: поскольку эти концепции плохо работают вместе, в Spring Data Redis отсутствует API для транзакционного использования.