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

Spring数据redis并发问题

朱明知
2023-03-14

我在使用spring redis数据的多线程时遇到了一个大问题,它很容易复制,我认为我遗漏了一些琐碎的东西。

如果我在执行保存操作时查询CrudRepository,它有时(高达60%)在Redis上找不到记录。

  • 一个简单的Spring启动项目(2.3.0. RELEASE)
  • 运行redis的docker

尽管可以在上面的链接中找到完整的代码,但这是主要组件:

@Repository
public interface MyEntityRepository extends CrudRepository<MyEntity, Integer> {

}
@RedisHash("my-entity")
public class MyEntity implements Serializable {

    @Id
    private int id1;

    private double attribute1;
    private String attribute2;
    private String attribute3;
    @GetMapping( "/my-endpoint")
    public ResponseEntity<?> myEndpoint () {

        MyEntity myEntity = new MyEntity();
        myEntity.setAttribute1(0.7);
        myEntity.setAttribute2("attr2");
        myEntity.setAttribute3("attr3");
        myEntity.setId1(1);

        myEntityRepository.save(myEntity);//create it in redis

        logger.info("STARTED");

        for (int i = 0; i < 100; i++){
            new Thread(){
                @Override
                public void run() {
                    super.run();

                    myEntity.setAttribute1(Math.random());

                    myEntityRepository.save(myEntity); //updating the entity

                    Optional<MyEntity> optionalMyEntity = myEntityRepository.findById(1);
                    if (optionalMyEntity.isPresent()) {
                        logger.info("found");
                    }else{
                        logger.warning("NOT FOUND");
                    }
                }
            }.start();

        }

        return ResponseEntity.noContent().build();
    }

2020-05-26 07:52:53.769  INFO 30655 --- [nio-8080-exec-2] my-controller-logger                     : STARTED
2020-05-26 07:52:53.795  INFO 30655 --- [     Thread-168] my-controller-logger                     : found
2020-05-26 07:52:53.798  WARN 30655 --- [     Thread-174] my-controller-logger                     : NOT FOUND
2020-05-26 07:52:53.798  WARN 30655 --- [     Thread-173] my-controller-logger                     : NOT FOUND
2020-05-26 07:52:53.806  INFO 30655 --- [     Thread-170] my-controller-logger                     : found
2020-05-26 07:52:53.806  WARN 30655 --- [     Thread-172] my-controller-logger                     : NOT FOUND
2020-05-26 07:52:53.812  WARN 30655 --- [     Thread-175] my-controller-logger                     : NOT FOUND
2020-05-26 07:52:53.814  WARN 30655 --- [     Thread-176] my-controller-logger                     : NOT FOUND
2020-05-26 07:52:53.819  WARN 30655 --- [     Thread-169] my-controller-logger                     : NOT FOUND
2020-05-26 07:52:53.826  INFO 30655 --- [     Thread-171] my-controller-logger                     : found
2020-05-26 07:52:53.829  INFO 30655 --- [     Thread-177] my-controller-logger                     : found

所以简单地说,有10个线程,其中6个没有在db中找到结果。

如上所述,将redis替换为Spring data redis至少包含9个操作。

因此,要替换redis中的值,它必须删除哈希、索引,然后再次添加新哈希和新索引,也许一个线程正在执行此操作,而其他线程试图通过索引查找值,而此索引尚未添加。

我认为spring data with data redis几乎不可能有这样的bug,所以我想知道我对data redis或redis有什么不理解。由于redis具有并发性,我认为可能会发生一些不同的事情,但在提供的示例中似乎是这样的。。。

提前感谢你们所有人

共有2个答案

沃博裕
2023-03-14

您有一个MyEntity实例:

MyEntity myEntity = createEntity();

然后,您已经启动了10个线程,所有这些线程都在更新一个对象myEntity。设置

然后将其另存为myEntityRepository。保存(myEntity) ,不可能知道保存了什么值,因为所有线程都在竞争插入自己的值。

当你调用myEntityRepository时。保存时,它可能正在保存(再次)另一个线程写入myEntity的值。所以这个线程从来没有机会将它的价值写入回购协议,因此你不会找到它!

我没有穿过@RedisHash,所以我可能错了,但我认为每次要保存记录时都需要创建一个新的实体对象。

与您的代码无关的另一个问题是无限线程创建(除非您不打算在生产中使用它)。

章睿
2023-03-14

这张罚单也引发了同样的问题。

故意选择该行为是为了避免残留的哈希条目。删除哈希可以确保一致的状态,并避免不再是哈希一部分的其他条目。
Redis存储库操作不是原子的。

所以它不是原子的。
并在票证中建议,解决方案将使用ParalUpdate

下面是一个片段,例如

    @Autowired
    private RedisKeyValueTemplate redisKVTemplate;
    ...
    // id is the @Id value of the entity
    private void update(Integer id) {
        PartialUpdate update = new PartialUpdate<MyEntity>(id, MyEntity.class)
                .set("attribute1", Math.random());
        redisKVTemplate.update(update);
    }

参考:
使用spring-data-redis更新redis中的实体

 类似资料:
  • 我正在使用Spring data redis和jedis与aspectJ进行日志记录。但是得到以下错误。请帮助解决此错误。我在这上面花了很多时间,但无法解决它。 我使用的是Spring数据redis 1.4.1,jedis-2.6.1和Redis-2.8 错误详情:- 下面是使用spring data redis的redis Sentinel配置的Java配置文件 下面是用于日志记录的Aspect

  • 我使用spring boot data redis连接到redis群集,使用版本2.1.3,配置如下: 但是,在操作过程中,始终会收到警告异常消息,如下所示: 这似乎是莴苣的问题,如何映射远程主机

  • 我正在尝试将ElastiCache设置为与Java应用程序一起使用。我的设置基于以下文档:https://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/BestPractices.html Java(8)应用程序运行的EC2实例位于专有网络中。我在VPC和非VPC中都尝试了ElastiCache实例。然而,我总是, 如果我自己在EC2

  • 我们有一个关于Spring框架的项目。它包含具有以下配置的Spring Security性: 它可以在一个Apache Tomcat服务器上工作。如果我尝试从另一个浏览器登录,我以前的http会话将过期。 null 所有这些方法都不起作用。我还发现了这个问题:https://github.com/spring-projects/spring-session/issues/65,它是两年前实现的。有

  • 问题内容: 我用作spring Web应用程序的数据存储,并用作与之交互的客户端。 我用来存储一个具有多个字段的对象。我可以使用method 一次将所有字段放入,但是我无法一次获取整个对象,而是使用method 来获取每个字段。 我想知道有什么办法可以像支持中的操作那样吗? 问题答案: DefaultRedisMap.entrySet()或BoundHashOperations.entries()

  • 本文向大家介绍如何解决 Redis 的并发竞争 Key 问题?相关面试题,主要包含被问及如何解决 Redis 的并发竞争 Key 问题?时的应答技巧和注意事项,需要的朋友参考一下 所谓 Redis 的并发竞争 Key 的问题也就是多个系统同时对一个 key 进行操作,但是最后执行的顺序和我们期望的顺序不同,这样也就导致了结果的不同! 推荐一种方案:分布式锁(zookeeper 和 redis 都可