当前位置: 首页 > 知识库问答 >
问题:

Spring Boot:Redis CRUD存储库findById或findAll始终返回可选值。空(空)

尹臻
2023-03-14

嗨团队,

我正在使用Spring Boot 2.3.12。内部使用Spring Data Redis 2.3.9的版本。作为托管依赖项发布。

当我试图使用Spring Boot CRUD存储库将对象保存到Redis缓存时,它正在毫无错误地存储,我可以通过Redis管理器看到存储的对象。

但是,当我尝试使用相同的id(即使用CRUD repository的findById()方法)获取相同的对象时,我找不到它。

此外,当我在同一个crudepository对象上尝试findAll()时,我得到了可选选项。空结果很奇怪,因为findAll()应该返回存储库中的所有记录。

我在下面添加了配置、存储库和模型类代码以及一些截图供您阅读。

请注意:我知道在这个平台上有很多类似的问题与这个问题有关,我也尝试了这些问题的解决方案,但这对我来说不起作用。

这个问题的任何解决方案都会非常有用。

模型类:

package com.test.cache.entity;
 
import java.util.concurrent.TimeUnit;
 
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.TimeToLive;
import org.springframework.data.redis.core.index.Indexed;
 
import lombok.AllArgsConstructor;
import lombok.Data;
 
@Data
@AllArgsConstructor
@RedisHash("OTPValidationLogCache")
public class OTPValidationLogCache {
 
@Id
@Indexed
private String id;

@Indexed
private int validationFailureCount;
 
@TimeToLive(unit = TimeUnit.MILLISECONDS)
private long expiry;

}

存储库:

package com.test.cache.repository;
 
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
 
import com.test.cache.entity.OTPValidationLogCache;
 
@Repository
public interface OTPValidationLogCacheRepository extends CrudRepository<OTPValidationLogCache, String> {
 
}

Redis配置类:

package com.test.configuration;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
 
import java.time.Duration;
 
@Configuration
@EnableRedisRepositories(basePackages = "com.test")
public class RedisConfig {
 
public static  final long REDIS_CONNECT_TIMEOUT_SECS = 10L;
 
@Bean
public RedisStandaloneConfiguration redisStandaloneConfiguration() {
final RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName("*******");
redisStandaloneConfiguration.setPort(6379);
redisStandaloneConfiguration.setPassword(RedisPassword.of("**********"));
//Credentials hidden for code sharing purpose.
return redisStandaloneConfiguration;
}
 
@Bean
public JedisConnectionFactory redisConnectionFactory() {
final JedisClientConfiguration jedisClientConfiguration = JedisClientConfiguration.builder()
.connectTimeout(Duration.ofSeconds(REDIS_CONNECT_TIMEOUT_SECS))
.useSsl()
.build();
 
    return new JedisConnectionFactory(redisStandaloneConfiguration(), jedisClientConfiguration);
}
 
@Bean
public RedisTemplate<String, Object> redisTemplate() {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory());
    return template;
}
}

Redis Manager屏幕截图:

Eclipse IDE-调试屏幕截图:

共有2个答案

澹台展鹏
2023-03-14

你需要为你的实体有相同的包,我通过提取一个库并把我的实体放在那里来解决这个问题

你可以在这里找到解释:https://github.com/spring-projects/spring-data-redis/issues/2114

尚俊楠
2023-03-14

我也向GitHub上的spring data redis repository提出了一个缺陷,但该缺陷被该存储库的一名维护人员关闭,甚至没有发布任何适当的解决方案。他只是提到了一个已经解决的问题,甚至没有发布任何解决方案。以下是与该问题的链接。

https://github.com/spring-projects/spring-data-redis/issues/2130

因此,在做一些研究时,我遇到了一个解决方案,我在这里分享,它在我的案例中起作用。

解决方案是不使用Spring Boot实现的默认CRUD存储库方法,而是编写自己的存储库类,其中包含从Redis缓存存储和获取数据的标准方法。就这样,现在您应该能够在项目中使用存储库方法存储/获取数据。

我在下面贴一个例子以供参考。

自定义存储库接口

package com.test.cache.repository;

import java.io.IOException;
import java.util.Map;

import com.test.cache.entity.OTPValidationLogCache;

public interface OTPValidationLogCacheRepository {

    void save(OTPValidationLogCache customer);
    OTPValidationLogCache find(Long id);
    Map<?,?> findAll() throws IOException;
    void update(OTPValidationLogCache customer);
    void delete(Long id);
}

自定义存储库接口实现

package com.test.cache.repository;

import java.io.IOException;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ScanOptions.ScanOptionsBuilder;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.test.cache.entity.OTPValidationLogCache;
import com.test.configuration.AppConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;

@Repository
public class OTPValidationLogCacheRepositoryImpl implements OTPValidationLogCacheRepository {
    
    private String key;
    
    private RedisTemplate redisTemplate;
    private HashOperations hashOperations;
    private ObjectMapper objMapper;
    
    @Autowired
    public OTPValidationLogCacheRepositoryImpl(RedisTemplate redisTemplate, ObjectMapper objmapper) {
        this.redisTemplate = redisTemplate;
        this.objMapper = objmapper;
    }
    
    @PostConstruct
    private void init() {
        hashOperations = redisTemplate.opsForHash();
    }
    
    @Override
    public void save(OTPValidationLogCache otpvalCache) {
        hashOperations.put(key.concat(otpvalCache.getId().toString()), otpvalCache.getId(), otpvalCache);
        setExpiryTime(key.concat(String.valueOf(otpvalCache.getId())), AppConfig.getUserBanDurationInSeconds());
    }

    @Override
    public OTPValidationLogCache find(Long id) {
        return (OTPValidationLogCache) hashOperations.get(key.concat(String.valueOf(id)), id);
    }

    @Override
    public Map findAll() throws IOException {
        Map<Integer, OTPValidationLogCache> values = Maps.newHashMap();
        Cursor c =  hashOperations.scan(OTPValidationLogCache.class, new ScanOptionsBuilder().match(key.concat("*")).build());
        AtomicInteger count = new AtomicInteger(1);
        c.forEachRemaining(element ->
                {
                    values.put(count.getAndIncrement(), objMapper.convertValue(element, OTPValidationLogCache.class));
                }
                );
        c.close();
        return values;
    }

    @Override
    public void update(OTPValidationLogCache customer) {
        hashOperations.put(key, customer.getId(), customer);
    }

    @Override
    public void delete(Long id) {
        hashOperations.delete(key, id);
    }
    
    private void setExpiryTime(String key, Long timeout)
    {
        redisTemplate.expire(key, Duration.ofSeconds(timeout));
    }

    public synchronized void setKey(String key)
    {
        this.key = key;
    }
}

希望这能帮助将来可能遇到这个问题的其他人。

此外,对于这个问题,还有一个选择,那就是切换到不同的库提供商,例如Redisson,但是,我还没有尝试过,所以如果您愿意,您可以尝试并检查。

 类似资料:
  • 我试图获取一个列表从数据库和findAll()返回空列表。我有多个jpa存储库,但只有一个不工作。这是代码: 这就是实体: 当我调用product类别epository.findAll()时,它返回空列表,因此我在数据库中有许多条目。谢谢你的帮助!

  • 问题内容: 我正在尝试从存储过程中获取返回值,但它始终返回0。 C#代码 SP 在所有情况下,它都返回0。我不知道问题所在。 问题答案: 我尝试了类似您的代码,并且可以按预期工作。 但是,您的代码中两次调用ExecuteNonQuery。 首次调用时,将按预期插入记录,然后为返回值添加参数并再次执行命令。但是现在记录已存在,并且存储过程始终落在else块中,因此始终返回零。

  • java java 在TaskServiceImpl.java.FindAll(pageRequest)中返回NULL。我不太熟悉Mockito,想知道用它创建模拟存储库是否会导致问题?当我这样做时,它工作得很好。findall()没有分页。我使用PagingAndSortingRepository中的findAll(Pageable)方法有问题吗?谢了!

  • 我正在尝试使用JpaRepository、spring boot和mysql发布文章 我有一张像这样的桌子 每当我尝试保存数据时,无论我传递什么值,列user总是0。 存储库如下所示 控制器如下所示

  • 问题内容: 在我的创建表脚本中,我已将hasMultipleColors字段定义为BIT: 运行INSERT时,不会对此字段或其他BIT字段引发警告,但是选择行将显示所有BIT值均为空白。 从命令行手动尝试更新这些记录会产生奇怪的效果-显示该记录已匹配并已更改(如果适用),但始终显示为空白。 服务器版本:5.5.24-0ubuntu0.12.04.1(Ubuntu) 有什么想法吗? 问题答案: 您

  • 我为此使用了一个服务类,但为了最小的可重复示例而删除了它。目前findAll()正在返回一个空数组,而它应该从h2返回一个带有员工实体json的数组。我仍然不清楚Spring如何将数据处理到h2数据库中,所以我想这可能是我的问题的根源。 控制器: 存储库: 实体: 数据sql: schema.sql: