我在使用spring-redis-data和多线程时遇到了一个大问题,这个问题非常容易重现,以至于我认为可能是我错过了一些微不足道的东西。
直奔主题
如果我在执行保存操作时查询CrudRepository,有时候(高达60%)Redis上并没有找到记录。
环境
代码
尽管可以在上面的链接中找到全部代码,但这些是主要组件:
CrudRepository
@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个线程在数据库中找不到结果。
使用Spring Data Redis进行替换
如此处所述,使用Spring Data Redis进行Redis的替换至少包含9个操作。
第一个结论
因此,要在Redis中替换一个值,必须先删除哈希表和索引,然后再添加新哈希表和新索引,也许一个线程正在执行这些操作的中间阶段,而另一个线程尝试按索引查找该值,但该索引尚未被添加。
第二个结论
我认为Spring Data Redis不太可能有这样的bug,所以我想知道我没有理解Data Redis或Redis的哪些方面。由于Redis具有并发性,我认为可能会发生一些不同的事情,但根据提供的示例似乎不是这种情况...
提前感谢大家。
run
方法的内容,以使操作原子化。 - Kartik