Backend Development 11 min read

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:

<code>return redisTemplate.opsForValue().increment("count", 1);</code>

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.

BackendJavaRedisSpringBootTransactional
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

login 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.