在我们的付款系统中,使用了非常简单的缓存方式。我们有本地的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("persons") @Entity @Table(name = "persons") public class Person implements Serializable { @Id @javax.persistence.Id private Long personId; private String name; private String surname; private String role; private Long teamId; @Column(name = "PERSON_ID") public Long getPersonId() { return personId; } public void setPersonId(Long personId) { this.personId = personId; } @Column(name = "NAME") public String getName() { return name; } public void setName(String name) { this.name = name; } @Column(name = "SURNAME") public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; } @Column(name = "ROLE") public String getRole() { return role; } public void setRole(String role) { this.role = role; } @Column(name = "TEAM_ID") public Long getTeamId() { return teamId; } public void setTeamId(Long teamId) { this.teamId = teamId; } |
此处的KeySpace注释表示,hazelcast 将使用名为“persons”的IMap将数据保存在内存中。
- 第三步
MapLoader实现将数据库和Hazelcast粘合在一起:
@Component public class HazelcastMapStore implements ApplicationContextAware, MapLoader<Long, Person> { private static PersonsJPARepository personsJPARepository; @Override public Person load(Long personId) { System.out.println("Loading by key: "+personId); return personsJPARepository.findById(personId).get(); } @Override public Map<Long, Person> loadAll(Collection<Long> collection) { System.out.println("Loading collections of IDS: "); Map<Long, Person> result = new HashMap<>(); for (Long key : collection) { Person productMap = this.load(key); if (productMap != null) { result.put(key, productMap); } } return result; } @Override public Iterable<Long> loadAllKeys() { System.out.println("Getting all the keys!"); return personsJPARepository.findAllId(); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { personsJPARepository = applicationContext.getBean(PersonsJPARepository.class); } |
MapLoader已准备就绪,现在每次当请求的实体不在内存中时,Hazelcast都会命中MapLoader.load(personId)其他两种方法只是预热缓存方法,用于在第一次缓存命中之前加载缓存的数据。
- 第四步
创建"persons" IMap,并连接到已经创建的HazelcastMapStore。
@Configuration public class HazelcastConfiguration { @Bean public Config hazelcastConfig(@Lazy HazelcastMapStore mapStore) { return new Config().setInstanceName("hazelcast-instance").addMapConfig( new MapConfig().setName("persons") .setMapStoreConfig( new MapStoreConfig().setEnabled(true).setInitialLoadMode(MapStoreConfig.InitialLoadMode.EAGER) .setImplementation(mapStore) )); } @Bean public HazelcastInstance hazelcastInstance(Config config) { return Hazelcast.newHazelcastInstance(config); } |
如果在将您的存储库连接到MapLoader时遇到问题,请查看此 Stackoverflow讨论
- 第五步
配置用于Hazelcast(缓存)和JPA(访问H2 DB)的Spring数据存储库
@SpringBootApplication(exclude = { HazelcastAutoConfiguration.class }) @EnableHazelcastRepositories(basePackages={"com.example.hazelcast.demo.repositories.hz"}) @EnableJpaRepositories(basePackages={"com.example.hazelcast.demo.repositories.jpa"}) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } |
EnableHazelcastRepositories,EnableJpaRepositories只是说明Spring数据存储库的位置。
这是完整的代码:
package com.example.hazelcast.demo.repositories.hz; import com.example.hazelcast.demo.model.Person; import org.springframework.data.hazelcast.repository.HazelcastRepository; public interface PersonsHazelcastRepository extends HazelcastRepository<Person, Long> { Person findPersonByPersonId(Long personId); } package com.example.hazelcast.demo.repositories.jpa; import com.example.hazelcast.demo.model.Person; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; public interface PersonsJPARepository extends CrudRepository<Person, Long> { @Query("SELECT n.id FROM Person n") Iterable<Long> findAllId(); } |
猜你喜欢