使用Hazelcast作为Spring数据存储库的开源案例

微信扫一扫,分享到朋友圈

使用Hazelcast作为Spring数据存储库的开源案例

在我们的付款系统中,使用了非常简单的缓存方式。我们有本地的 EhCache
,它工作得很好,是在 JDBC
层提供的。这种设计的缺点是:

  • 这是本地缓存。没有数据更改传播到其他节点。
  • 不涉及JPA。

解决上述问题的好方法是将 Hazelcast
包装到 Spring Data API中,
称为 spring-data-hazelcast

在该存储库中,我将向您展示如何使用H2数据库支持的Hazelcast Spring Data API 构建完整的 只读
缓存。

首先,一定要看一下 spring-data-jpa-hazelcast-migration
如果您是Spring Data JPA新手,那么本指南将非常有帮助。然后确保您熟悉 Hazelcast MapLoader

使用HazelcastRead-through缓存

  • maven依赖
<properties>
<java.version>1.8</java.version>
<spring-data-hazelcast-version>2.2.5</spring-data-hazelcast-version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>spring-data-hazelcast</artifactId>
<version>${spring-data-hazelcast-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

spring-data-hazelcast插件已经打包好了hazelcast,因此无需担心版本问题。大赞!

  • 第二步

缓存实体是存储在H2数据库,并通过MapLoader提供给hazelcast的,该实体是此read-through体系结构的引擎:

@KeySpace(<font>"persons"</font><font>)
@Entity
@Table(name = </font><font>"persons"</font><font>)
<b>public</b> <b>class</b> Person implements Serializable {
@Id
@javax.persistence.Id
<b>private</b> Long personId;
<b>private</b> String name;
<b>private</b> String surname;
<b>private</b> String role;
<b>private</b> Long teamId;
@Column(name = </font><font>"PERSON_ID"</font><font>)
<b>public</b> Long getPersonId() {
<b>return</b> personId;
}
<b>public</b> <b>void</b> setPersonId(Long personId) {
<b>this</b>.personId = personId;
}
@Column(name = </font><font>"NAME"</font><font>)
<b>public</b> String getName() {
<b>return</b> name;
}
<b>public</b> <b>void</b> setName(String name) {
<b>this</b>.name = name;
}
@Column(name = </font><font>"SURNAME"</font><font>)
<b>public</b> String getSurname() {
<b>return</b> surname;
}
<b>public</b> <b>void</b> setSurname(String surname) {
<b>this</b>.surname = surname;
}
@Column(name = </font><font>"ROLE"</font><font>)
<b>public</b> String getRole() {
<b>return</b> role;
}
<b>public</b> <b>void</b> setRole(String role) {
<b>this</b>.role = role;
}
@Column(name = </font><font>"TEAM_ID"</font><font>)
<b>public</b> Long getTeamId() {
<b>return</b> teamId;
}
<b>public</b> <b>void</b> setTeamId(Long teamId) {
<b>this</b>.teamId = teamId;
}
</font>

此处的KeySpace注释表示,hazelcast 将使用名为“persons”的IMap将数据保存在内存中。

  • 第三步

MapLoader实现将数据库和Hazelcast粘合在一起:

@Component
<b>public</b> <b>class</b> HazelcastMapStore implements ApplicationContextAware, MapLoader<Long, Person> {
<b>private</b> <b>static</b> PersonsJPARepository personsJPARepository;
@Override
<b>public</b> Person load(Long personId) {
System.out.println(<font>"Loading by key: "</font><font>+personId);
<b>return</b> personsJPARepository.findById(personId).get();
}
@Override
<b>public</b> Map<Long, Person> loadAll(Collection<Long> collection) {
System.out.println(</font><font>"Loading collections of IDS: "</font><font>);
Map<Long, Person> result = <b>new</b> HashMap<>();
<b>for</b> (Long key : collection) {
Person productMap = <b>this</b>.load(key);
<b>if</b> (productMap != <b>null</b>) {
result.put(key, productMap);
}
}
<b>return</b> result;
}
@Override
<b>public</b> Iterable<Long> loadAllKeys() {
System.out.println(</font><font>"Getting all the keys!"</font><font>);
<b>return</b> personsJPARepository.findAllId();
}
@Override
<b>public</b> <b>void</b> setApplicationContext(ApplicationContext applicationContext) throws BeansException {
personsJPARepository = applicationContext.getBean(PersonsJPARepository.<b>class</b>);
}
</font>

MapLoader已准备就绪,现在每次当请求的实体不在内存中时,Hazelcast都会命中MapLoader.load(personId)其他两种方法只是预热缓存方法,用于在第一次缓存命中之前加载缓存的数据。

  • 第四步

创建”persons” IMap,并连接到已经创建的HazelcastMapStore。

@Configuration
<b>public</b> <b>class</b> HazelcastConfiguration {
@Bean
<b>public</b> Config hazelcastConfig(@Lazy HazelcastMapStore mapStore) {
<b>return</b> <b>new</b> Config().setInstanceName(<font>"hazelcast-instance"</font><font>).addMapConfig(
<b>new</b> MapConfig().setName(</font><font>"persons"</font><font>)
.setMapStoreConfig(
<b>new</b> MapStoreConfig().setEnabled(<b>true</b>).setInitialLoadMode(MapStoreConfig.InitialLoadMode.EAGER)
.setImplementation(mapStore)
));
}
@Bean
<b>public</b> HazelcastInstance hazelcastInstance(Config config) {
<b>return</b> Hazelcast.newHazelcastInstance(config);
}
</font>

如果在将您的存储库连接到MapLoader时遇到问题,请查看此 Stackoverflow讨论

  • 第五步

配置用于Hazelcast(缓存)和JPA(访问H2 DB)的Spring数据存储

@SpringBootApplication(exclude = {
HazelcastAutoConfiguration.<b>class</b>
})
@EnableHazelcastRepositories(basePackages={<font>"com.example.hazelcast.demo.repositories.hz"</font><font>})
@EnableJpaRepositories(basePackages={</font><font>"com.example.hazelcast.demo.repositories.jpa"</font><font>})
<b>public</b> <b>class</b> DemoApplication {
<b>public</b> <b>static</b> <b>void</b> main(String[] args) {
SpringApplication.run(DemoApplication.<b>class</b>, args);
}
}
</font>

EnableHazelcastRepositories,EnableJpaRepositories只是说明Spring数据存储库的位置。

这是完整的代码:

<b>package</b> com.example.hazelcast.demo.repositories.hz;
<b>import</b> com.example.hazelcast.demo.model.Person;
<b>import</b> org.springframework.data.hazelcast.repository.HazelcastRepository;
<b>public</b> <b>interface</b> PersonsHazelcastRepository <b>extends</b> HazelcastRepository<Person, Long> {
Person findPersonByPersonId(Long personId);
}
<b>package</b> com.example.hazelcast.demo.repositories.jpa;
<b>import</b> com.example.hazelcast.demo.model.Person;
<b>import</b> org.springframework.data.jpa.repository.Query;
<b>import</b> org.springframework.data.repository.CrudRepository;
<b>public</b> <b>interface</b> PersonsJPARepository <b>extends</b> CrudRepository<Person, Long> {
@Query(<font>"SELECT n.id FROM Person n"</font><font>)
Iterable<Long> findAllId();
}
</font>

PS5游戏发布会:《最终幻想16》正式公开限时独占PS平台

上一篇

PS5初期游戏阵容确保 PS Plus会员畅享PS4大作

下一篇

你也可能喜欢

使用Hazelcast作为Spring数据存储库的开源案例

长按储存图像,分享给朋友