Why Does Redis Increment Return Null in Spring @Transactional? Root Cause and Fix

This article analyzes why Redis's increment operation returns null when used inside a Spring @Transactional method with transaction support enabled, details the debugging steps, experiments, and presents two practical solutions to prevent the issue.

macrozheng
macrozheng
macrozheng
Why Does Redis Increment Return Null in Spring @Transactional? Root Cause and Fix

Introduction

In a production environment, customer service staff encountered a recurring failure when creating service events each morning. The failure was resolved temporarily by restarting the microservice, after which the creation succeeded until the next morning.

Problem Description

The service creates a distributed ID for each event using Redis's increment operation:

return redisTemplate.opsForValue().increment("count", 1);

Every morning the increment call returned null, causing the subsequent logic to fail. Restarting the microservice restored normal behavior.

Investigation

2.1 First Hypothesis – Connection Leak

It was suspected that a large number of jobs at night left many Redis connections unclosed, causing the morning operation to fail. However, other Redis‑using features worked fine, so this hypothesis was discarded.

2.2 Second Hypothesis – Redis Transaction

Redis documentation states that increment returns null when used inside a pipeline or a transaction. The service implementation class is annotated with @Transactional, which might affect the Redis call.

2.3 Verifying the Transaction Hypothesis

A table of test cases showed that when @Transactional is present, the Redis increment returns null. A demo program without the annotation always returned a valid number, confirming that the annotation alone does not cause the issue.

2.4 Third Hypothesis – Redis Transaction Support Enabled

Another developer had enabled Redis transaction support and used multi / exec in nightly jobs. Enabling transaction support causes Redis commands to be queued, and increment returns null until the transaction is committed.

2.5 Experimental Verification

Four scenarios were tested:

Enable Redis transaction support and execute increment inside a @Transactional method – null returned.

Enable Redis transaction support and execute increment in a non‑transactional method – valid result.

Disable transaction support – always valid result.

The experiments confirmed that only the combination of Redis transaction support and Spring @Transactional caused the null return.

Root Cause Analysis

When setEnableTransactionSupport(true) is set, Spring binds a Redis connection to the current transaction. The call to increment is then executed inside a Redis MULTI block, which queues the command and returns null immediately. After the Spring transaction commits, the queued commands are executed, and the key value is incremented, but the original call has already returned null.

Solutions

Solution 1 – Disable Transaction Support After Use

Manually turn off Redis transaction support after each transactional operation. This approach works but can still produce null if a Redis command is executed inside a @Transactional method while the transaction support is active.

Solution 2 – Separate RedisTemplate Beans

Create two StringRedisTemplate beans: stringRedisTemplate – without transaction support, used for normal commands. stringRedisTemplateTransaction – with transaction support, used only for explicit Redis transactions.

Inject the appropriate bean where needed. This isolates transactional Redis usage from regular Redis operations, ensuring that increment returns the expected value inside Spring @Transactional methods.

Implementation Example

Define a configuration class that declares both beans, then inject them into services accordingly. The demo showed that after applying the second solution, the Redis increment operation consistently returned the correct count.

Conclusion

Enabling Redis transaction support together with Spring's @Transactional causes Redis commands to be queued, leading to null returns for increment operations. Using separate RedisTemplate instances or disabling transaction support after use resolves the issue.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaredisSpringBoottransactional
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.