spring-data-gemfire - Apache Geode crud 存储库 findById() 返回错误的数组
问题描述
我正在使用 apache geode 1.13.0
数据类很简单,它包含 1 个 ArrayList 和 1 个 HashMap
数据正确存储在 geode 上,但 repository.findById() 返回错误的数组和地图
repository.findAll() 虽然效果很好
数据是
id | someList | someMap
-- | --------- | ---------------------------------
1 | [1,2,3,4] | {"1":"a","2":"b","3":"c","4":"d"}
2 | [2,3,4] | {"4":"d","2":"b","3":"c"}
3 | [3,4] | {"4":"d","3":"c"}
4 | null | {"4":"d"}
5 | null | null
而 findById 检索
Class1{id=1, someList=[3, 4], someMap={4=d}}
Class1{id=2, someList=[3, 4], someMap={4=d}}
Class1{id=3, someList=[3, 4], someMap={4=d}}
Class1{id=4, someList=null, someMap={4=d}}
Class1{id=5, someList=null, someMap=null}
逻辑在 MyRunner.java
可能是什么问题呢?
这是课程
....
@Region("TestRegion")
public class Class1 implements PdxSerializable {
@Id
Integer id;
ArrayList<Integer> someList;
HashMap<Integer, String> someMap;
public Class1() {}
public Class1(Integer id, ArrayList<Integer> someList, HashMap<Integer, String> someMap) {
this.id = id;
this.someList = someList;
this.someMap = someMap;
}
@Override
public String toString() {
String ret;
ret = "Class1";
ret += "{id=";
if (id == null) { ret += "null"; } else { ret += id.toString(); }
ret += ", someList=";
if (someList == null) { ret += "null"; } else { ret += someList.toString(); }
ret += ", someMap=";
if (someMap == null) { ret += "null"; } else { ret += someMap.toString(); }
ret += "}";
return ret;
}
@Override
public void toData(PdxWriter out) throws PdxFieldAlreadyExistsException, PdxSerializationException {
out.writeInt("id", id);
out.writeObject("someList", someList);
out.writeObject("someMap", someMap);
}
@Override
public void fromData(PdxReader in) throws PdxFieldTypeMismatchException, PdxSerializationException {
id = in.readInt("id");
someList = (ArrayList<Integer>)in.readObject("someList");
someMap = (HashMap<Integer, String>)in.readObject("someMap");
}
}
存储库
@Repository
public interface GeodeRepository extends CrudRepository<Class1, Integer> {
}
geode 配置类
.....
@EnableEntityDefinedRegions(basePackageClasses = Class1.class, clientRegionShortcut = ClientRegionShortcut.CACHING_PROXY)
@EnableGemfireRepositories(basePackageClasses = GeodeRepository.class)
@Configuration
class GeodeConfiguration {
}
主要的
....
@SpringBootApplication
class SpringbootCmdTest {
public static void main(String[] args) {
SpringApplication.run(SpringbootCmdTest.class, args);
}
}
MyRunner 类
....
@Component
public class MyRunner implements CommandLineRunner {
@Autowired
private GeodeRepository repository;
@Override
public void run(String... args) throws Exception {
//repository.deleteAll(); // doesn't work for partitioned regions as of 2020-11-02 https://jira.spring.io/browse/DATAGEODE-265
repository.deleteAll(repository.findAll());
ArrayList<Integer> l = new ArrayList<>();
HashMap<Integer, String> m = new HashMap<>();
Class1 obj;
Optional<Class1> o;
l.clear(); l.add(1); l.add(2); l.add(3); l.add(4);
m.clear(); m.put(1, "a"); m.put(2, "b"); m.put(3, "c"); m.put(4, "d");
obj = new Class1(1, l, m);
repository.save(obj);
l.clear(); l.add(2); l.add(3); l.add(4);
m.clear(); m.put(2, "b"); m.put(3, "c"); m.put(4, "d");
obj = new Class1(2, l, m);
repository.save(obj);
l.clear(); l.add(3); l.add(4);
m.clear(); m.put(3, "c"); m.put(4, "d");
obj = new Class1(3, l, m);
repository.save(obj);
m.clear(); m.put(4, "d");
obj = new Class1(4, null, m);
repository.save(obj);
obj = new Class1(5, null, null);
repository.save(obj);
System.out.println("\n-- findAll().foreach works -------------------------------");
repository.findAll().forEach((item) ->System.out.println(item.toString()));
System.out.println("\n-- optional directly to string. issue with the array and map. displays the last entry --");
System.out.println(repository.findById(1).toString());
System.out.println(repository.findById(2).toString());
System.out.println(repository.findById(3).toString());
System.out.println(repository.findById(4).toString());
System.out.println(repository.findById(5).toString());
System.out.println("\n-- first convert the optional to object. issue with the array and map. displays the last entry --");
o = repository.findById(1);
o.ifPresent(ob -> System.out.println(ob.toString()));
o = repository.findById(2);
o.ifPresent(ob -> System.out.println(ob.toString()));
o = repository.findById(3);
o.ifPresent(ob -> System.out.println(ob.toString()));
o = repository.findById(4);
o.ifPresent(ob -> System.out.println(ob.toString()));
o = repository.findById(5);
o.ifPresent(ob -> System.out.println(ob.toString()));
System.out.println("\n-- findAllById().foreach does not work either -------------------------------");
ArrayList<Integer> il = new ArrayList<>();
il.add(1); il.add(2); il.add(3); il.add(4); il.add(5);
repository.findAllById(il).forEach((item) ->System.out.println(item.toString()));
System.out.println("\n---------------------------------");
}
}
应用程序属性
spring.profiles.active = dev
logging.level.org.springframework.boot = INFO
logging.level.org.springframework.transaction = TRACE
logging.level.owa = DEBUG
logging.file.name = Test.log
spring.main.banner-mode=off
spring.profiles.include=common
spring.data.gemfire.pool.locators = localhost[2001]
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/><!-- lookup parent from repository -->
</parent>
<groupId>org.Test</groupId>
<artifactId>SpringbootCmdTest</artifactId>
<version>20.10.0</version>
<name>SpringbootCmdTest</name>
<description>Springboot Cmd Line For Testing</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.geode</groupId>
<artifactId>spring-geode-starter</artifactId>
<version>1.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.geode</groupId>
<artifactId>geode-core</artifactId>
<version>1.13.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.8.1</version>
<executions>
<execution>
<goals>
<goal>addSources</goal>
<goal>addTestSources</goal>
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>compileTests</goal>
<goal>removeStubs</goal>
<goal>removeTestStubs</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
gfsh 查询
gfsh>query --query="select * from /TestRegion"
Result : true
Limit : 100
Rows : 5
id | someList | someMap
-- | --------- | ---------------------------------
1 | [1,2,3,4] | {"1":"a","2":"b","3":"c","4":"d"}
2 | [2,3,4] | {"4":"d","2":"b","3":"c"}
3 | [3,4] | {"4":"d","3":"c"}
4 | null | {"4":"d"}
5 | null | null
输出
-- findAll().foreach works -------------------------------
Class1{id=1, someList=[1, 2, 3, 4], someMap={1=a, 2=b, 3=c, 4=d}}
Class1{id=2, someList=[2, 3, 4], someMap={4=d, 2=b, 3=c}}
Class1{id=3, someList=[3, 4], someMap={4=d, 3=c}}
Class1{id=4, someList=null, someMap={4=d}}
Class1{id=5, someList=null, someMap=null}
-- optional directly to string. issue with the array and map. displays the last entry --
Optional[Class1{id=1, someList=[3, 4], someMap={4=d}}]
Optional[Class1{id=2, someList=[3, 4], someMap={4=d}}]
Optional[Class1{id=3, someList=[3, 4], someMap={4=d}}]
Optional[Class1{id=4, someList=null, someMap={4=d}}]
Optional[Class1{id=5, someList=null, someMap=null}]
-- first convert the optional to object. issue with the array and map. displays the last entry --
Class1{id=1, someList=[3, 4], someMap={4=d}}
Class1{id=2, someList=[3, 4], someMap={4=d}}
Class1{id=3, someList=[3, 4], someMap={4=d}}
Class1{id=4, someList=null, someMap={4=d}}
Class1{id=5, someList=null, someMap=null}
-- findAllById().foreach does not work either -------------------------------
Class1{id=1, someList=[3, 4], someMap={4=d}}
Class1{id=2, someList=[3, 4], someMap={4=d}}
Class1{id=3, someList=[3, 4], someMap={4=d}}
Class1{id=4, someList=null, someMap={4=d}}
Class1{id=5, someList=null, someMap=null}
解决方案
注意:这种行为不是 Spring 独有的,可以单独使用 Apache Geode 重现。
由于您已clientRegionShortcut
设置为ClientRegionShortcut.CACHING_PROXY
,因此您的数据将同时存储在本地区域的服务器和客户端上。当你通过id访问数据时,首先检查本地区域,如果找到该条目,则返回它,如果没有找到它会调用服务器。
您只看到列表和地图的最新值的原因是因为本地区域通过引用保持不变m
,l
因此当您重用它们并更新它们的内容时,存储在本地区域中的值反映了更改为好吧,即使没有保存它们。您会看到正确的值findAll()
和查询,因为它们直接委托给服务器(它不通过引用保存值,因为它是一个单独的机器/进程)而不是本地区域。
有几种方法可以获得您期望的行为:
选项 1. 更改ClientRegionShortcut.CACHING_PROXY
为ClientRegionShortcut.PROXY
使值不会存储在本地,而是每次都从服务器检索。
选项 2。您可以在每次要添加条目时创建一个新的ArrayList
,而不是重复使用相同的对象。HashMap
例如,将l.clear()
andm.clear()
替换为l = new ArrayList<>()
and m = new HashMap<>()
。
推荐阅读
- ruby-on-rails - 在 Rails 查询中转义引号
- javascript - 在 JS 中具有编码挑战的一些方向/提示
- session - 我用的是django2.2.7内置的LoginView,首页模板和文章模板的request.user中获取的用户不一致
- git - 在 git 中创建具有多个项目的单个工作树
- reactjs - 如何从 GitLab 向其他人展示我的 React 应用程序?
- firebase - 是否可以在 Firebase Hosting 中独立于请求的 URL 重写 Cloud Function 调用结果?
- sql - 在 SQL 中组合 2 个表,包括不常见的字段
- python - 视差图只显示轮廓
- javascript - 如何使用 express 验证器
- git - 挑选一系列提交不起作用,但个别挑选工作