Skip to content
This repository was archived by the owner on Aug 25, 2022. It is now read-only.

Commit 8445420

Browse files
committed
Add Spring Data Hibernate example
1 parent 08ff834 commit 8445420

11 files changed

Lines changed: 635 additions & 8 deletions

File tree

mapstore/README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,24 @@
22

33
## Overview
44

5-
Hazelcast allows you to load and store the distributed map entries from/to a persistent data store such as a relational database.
5+
Hazelcast allows you to load and store the distributed map entries from/to a persistent data store such as a
6+
relational database.
67

7-
To do this, you can use Hazelcast’s `MapStore` and `MapLoader` interfaces.
8+
To do this, you can use Hazelcast’s `MapStore` and `MapLoader` interfaces.
89

910
### Terminology
11+
1012
| Term | Definition |
1113
| ------------- | ------------- |
1214
| MapLoader | [MapLoader](https://github.com/hazelcast/hazelcast/blob/master/hazelcast/src/main/java/com/hazelcast/map/MapLoader.java) is an SPI. When you provide a MapLoader implementation and request an entry (using IMap.get()) that does not exist in memory, MapLoader's load method loads that entry from the data store. This loaded entry is placed into the map and will stay there until it is removed or evicted. |
1315
| MapStore | [MapStore](https://github.com/hazelcast/hazelcast/blob/master/hazelcast/src/main/java/com/hazelcast/map/MapStore.java) is also an SPI. When a MapStore implementation is provided, an entry is also put into a user defined data store. MapStore extends MapLoader. Later in this document, by MapStore we mean both MapStore and MapLoader since they compose a full-featured MapStore CRUD SPI. |
1416
| MapStore Configuration | MapStore Configuration defines a MapStore implementation (class name or instance) and properties which control the way it works. |
1517

16-
1718
## Samples
18-
19+
1920
- [Hazelcast 3.X.X MapStore JDBC Sample](mapstore-sample-hazelcast3-jdbc/README.md)
2021
- [Hazelcast 4.X.X MapStore JDBC Sample](mapstore-sample-hazelcast4-jdbc/README.md)
22+
- [Hazelcast 4.X.X MapStore Spring Data JPA Sample](mapstore-sample-hazelcast4-spring-data-jpa/README.md)
2123
- [Hazelcast 3.X.X MapStore Mongo Sample](mapstore-sample-hazelcast3-mongodb/README.md)
2224
- [Hazelcast 4.X.X MapStore Mongo Sample](mapstore-sample-hazelcast4-mongodb/README.md)
2325

@@ -27,16 +29,14 @@ MapStore Samples can be easily built with the maven wrapper. You also need JDK 1
2729

2830
- Clone the Git repository.
2931
- Open the project directory
30-
- `./mvnw clean verify` to build and run all samples
31-
32+
- `./mvnw clean verify` to build and run all samples
3233

3334
## Reference
3435

3536
https://docs.hazelcast.org/docs/latest/manual/html-single/index.html#loading-and-storing-persistent-data
3637

37-
38-
3938
## F.A.Q.
4039

4140
- Why do we need to use `maven-shade-plugin`?
41+
4242
> In order to make sure, that all MapStore dependencies are available in the final JAR.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Hazelcast 4.X.X MapStore Spring Data JPA Sample
2+
3+
This is an example of how to use `MapStore` and `Spring Data JPA`.
4+
5+
Required properties:
6+
7+
- `driverClassName` - JDBC Driver class e.g. `com.mysql.cj.jdbc.Driver` for MySQL
8+
- `jdbcUrl` - JDBC URL, e.g. `jdbc:mysql://<host>:<port>/<database>`
9+
- `username` - database username
10+
- `password` - database password
11+
12+
## Classes
13+
14+
- [Person](src/main/java/sample/com/hazelcast/cloud/mapstore4/jpa/Person.java) Entity class
15+
- [PersonRepository](src/main/java/sample/com/hazelcast/cloud/mapstore4/jpa/PersonRepository.java) JPA repository
16+
for Person Entity.
17+
- [PersonMapStore](src/main/java/sample/com/hazelcast/cloud/mapstore4/jpa/JpaPersonMapStore.java) MapStore
18+
implementation for Person Entity.
19+
- [PersonMapStoreTest](src/test/java/sample/com/hazelcast/cloud/mapstore4/jpa/JpaPersonMapStoreTest.java) Person
20+
MapStore tests.
21+
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>com.hazelcast.cloud</groupId>
9+
<artifactId>mapstore-samples</artifactId>
10+
<version>0.1-SNAPSHOT</version>
11+
<relativePath>../pom.xml</relativePath>
12+
</parent>
13+
14+
<artifactId>mapstore-sample-hazelcast4-spring-data-jpa</artifactId>
15+
<packaging>jar</packaging>
16+
<version>0.1-SNAPSHOT</version>
17+
18+
<name>Hazelcast 4.x.x Map Store Spring Data JPA Sample</name>
19+
20+
<properties>
21+
<hazelcast-all.version>4.1</hazelcast-all.version>
22+
<testcontainers.version>1.16.2</testcontainers.version>
23+
<mysql.version>8.0.15</mysql.version>
24+
<HikariCP.version>4.0.3</HikariCP.version>
25+
<junit.version>4.13</junit.version>
26+
<logback-classic.version>1.2.3</logback-classic.version>
27+
<assertj-core.version>3.16.0</assertj-core.version>
28+
<lombok.version>1.18.12</lombok.version>
29+
<maven-shade-plugin.version>3.2.4</maven-shade-plugin.version>
30+
<spring-data-jpa.version>2.6.0</spring-data-jpa.version>
31+
<hibernate.version>5.4.32.Final</hibernate.version>
32+
</properties>
33+
34+
<dependencies>
35+
<dependency>
36+
<groupId>org.hibernate</groupId>
37+
<artifactId>hibernate-core</artifactId>
38+
<version>${hibernate.version}</version>
39+
</dependency>
40+
<dependency>
41+
<groupId>org.hibernate</groupId>
42+
<artifactId>hibernate-hikaricp</artifactId>
43+
<version>${hibernate.version}</version>
44+
</dependency>
45+
<dependency>
46+
<groupId>org.springframework.data</groupId>
47+
<artifactId>spring-data-jpa</artifactId>
48+
<version>${spring-data-jpa.version}</version>
49+
</dependency>
50+
<dependency>
51+
<groupId>mysql</groupId>
52+
<artifactId>mysql-connector-java</artifactId>
53+
<version>${mysql.version}</version>
54+
</dependency>
55+
<dependency>
56+
<groupId>com.zaxxer</groupId>
57+
<artifactId>HikariCP</artifactId>
58+
<version>${HikariCP.version}</version>
59+
</dependency>
60+
<dependency>
61+
<groupId>com.hazelcast</groupId>
62+
<artifactId>hazelcast-all</artifactId>
63+
<version>${hazelcast-all.version}</version>
64+
<scope>provided</scope>
65+
</dependency>
66+
<dependency>
67+
<groupId>org.projectlombok</groupId>
68+
<artifactId>lombok</artifactId>
69+
<version>${lombok.version}</version>
70+
<scope>provided</scope>
71+
</dependency>
72+
<dependency>
73+
<groupId>org.assertj</groupId>
74+
<artifactId>assertj-core</artifactId>
75+
<version>${assertj-core.version}</version>
76+
<scope>test</scope>
77+
</dependency>
78+
<dependency>
79+
<groupId>org.testcontainers</groupId>
80+
<artifactId>testcontainers</artifactId>
81+
<version>${testcontainers.version}</version>
82+
<scope>test</scope>
83+
</dependency>
84+
<dependency>
85+
<groupId>junit</groupId>
86+
<artifactId>junit</artifactId>
87+
<version>${junit.version}</version>
88+
<scope>test</scope>
89+
</dependency>
90+
<dependency>
91+
<groupId>org.testcontainers</groupId>
92+
<artifactId>mysql</artifactId>
93+
<version>${testcontainers.version}</version>
94+
<scope>test</scope>
95+
</dependency>
96+
<dependency>
97+
<groupId>ch.qos.logback</groupId>
98+
<artifactId>logback-classic</artifactId>
99+
<version>${logback-classic.version}</version>
100+
<scope>test</scope>
101+
</dependency>
102+
</dependencies>
103+
104+
<build>
105+
<plugins>
106+
<plugin>
107+
<groupId>org.apache.maven.plugins</groupId>
108+
<artifactId>maven-shade-plugin</artifactId>
109+
<version>${maven-shade-plugin.version}</version>
110+
<executions>
111+
<execution>
112+
<phase>package</phase>
113+
<goals>
114+
<goal>shade</goal>
115+
</goals>
116+
</execution>
117+
</executions>
118+
</plugin>
119+
</plugins>
120+
</build>
121+
122+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package sample.com.hazelcast.cloud.mapstore4.jpa;
2+
3+
import javax.persistence.EntityManagerFactory;
4+
import javax.sql.DataSource;
5+
6+
import com.zaxxer.hikari.HikariDataSource;
7+
import org.springframework.beans.factory.annotation.Value;
8+
import org.springframework.context.annotation.Bean;
9+
import org.springframework.context.annotation.Configuration;
10+
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
11+
import org.springframework.orm.jpa.JpaTransactionManager;
12+
import org.springframework.orm.jpa.JpaVendorAdapter;
13+
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
14+
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
15+
import org.springframework.transaction.PlatformTransactionManager;
16+
import org.springframework.transaction.annotation.EnableTransactionManagement;
17+
18+
@Configuration(proxyBeanMethods = false)
19+
@EnableTransactionManagement
20+
@EnableJpaRepositories
21+
public class JpaConfig {
22+
23+
@Bean(destroyMethod = "close")
24+
public HikariDataSource dataSource(@Value("${jdbcUrl}") String jdbcUrl,
25+
@Value("${username}") String username, @Value("${password}") String password,
26+
@Value("${driverClassName}") String driverClassName) {
27+
HikariDataSource dataSource = new HikariDataSource();
28+
dataSource.setJdbcUrl(jdbcUrl);
29+
dataSource.setUsername(username);
30+
dataSource.setPassword(password);
31+
dataSource.setDriverClassName(driverClassName);
32+
dataSource.setMaximumPoolSize(5);
33+
dataSource.setMinimumIdle(1);
34+
return dataSource;
35+
}
36+
37+
@Bean
38+
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
39+
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
40+
entityManager.setDataSource(dataSource);
41+
entityManager.setPackagesToScan("sample.com.hazelcast.cloud.mapstore4.jpa");
42+
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
43+
entityManager.setJpaVendorAdapter(vendorAdapter);
44+
return entityManager;
45+
}
46+
47+
@Bean
48+
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
49+
JpaTransactionManager transactionManager = new JpaTransactionManager();
50+
transactionManager.setEntityManagerFactory(entityManagerFactory);
51+
return transactionManager;
52+
}
53+
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package sample.com.hazelcast.cloud.mapstore4.jpa;
2+
3+
import java.util.Collection;
4+
import java.util.LinkedHashMap;
5+
import java.util.Map;
6+
import java.util.Properties;
7+
8+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
9+
import org.springframework.core.env.PropertiesPropertySource;
10+
11+
import com.hazelcast.core.HazelcastInstance;
12+
import com.hazelcast.logging.ILogger;
13+
import com.hazelcast.logging.Logger;
14+
import com.hazelcast.map.MapLoaderLifecycleSupport;
15+
import com.hazelcast.map.MapStore;
16+
17+
public class JpaPersonMapStore implements MapStore<Integer, Person>, MapLoaderLifecycleSupport {
18+
19+
private static final ILogger log = Logger.getLogger(JpaPersonMapStore.class);
20+
21+
private final AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
22+
23+
private PersonRepository personRepository;
24+
25+
@Override
26+
public void init(HazelcastInstance hazelcastInstance, Properties properties, String mapName) {
27+
log.info("JpaPersonMapStore::initializing");
28+
this.applicationContext.getEnvironment().getPropertySources().addFirst(new PropertiesPropertySource(
29+
"JpaPersonMapStore", properties));
30+
this.applicationContext.register(JpaConfig.class);
31+
this.applicationContext.refresh();
32+
this.personRepository = this.applicationContext.getBean(PersonRepository.class);
33+
log.info("JpaPersonMapStore::initialized");
34+
}
35+
36+
@Override
37+
public void destroy() {
38+
log.info("JpaPersonMapStore::destroying");
39+
this.applicationContext.close();
40+
log.info("JpaPersonMapStore::destroyed");
41+
}
42+
43+
@Override
44+
public void store(Integer key, Person value) {
45+
log.info(String.format("JpaPersonMapStore::store key %s value %s", key, value));
46+
this.personRepository.save(value);
47+
}
48+
49+
@Override
50+
public void storeAll(Map<Integer, Person> map) {
51+
log.info(String.format("JpaPersonMapStore::store all %s", map));
52+
for (Map.Entry<Integer, Person> entry : map.entrySet()) {
53+
store(entry.getKey(), entry.getValue());
54+
}
55+
}
56+
57+
@Override
58+
public void delete(Integer key) {
59+
log.info(String.format("JpaPersonMapStore::delete key %s", key));
60+
this.personRepository.deleteById(key);
61+
}
62+
63+
@Override
64+
public void deleteAll(Collection<Integer> keys) {
65+
log.info(String.format("JpaPersonMapStore::delete all %s", keys));
66+
keys.forEach(this::delete);
67+
}
68+
69+
@Override
70+
public Person load(Integer key) {
71+
log.info(String.format("JpaPersonMapStore::load by key %s", key));
72+
return this.personRepository.findById(key).orElse(null);
73+
}
74+
75+
@Override
76+
public Map<Integer, Person> loadAll(Collection<Integer> keys) {
77+
log.info(String.format("JpaPersonMapStore::loadAll by keys %s", keys));
78+
Map<Integer, Person> result = new LinkedHashMap<>();
79+
for (Integer key : keys) {
80+
Person person = load(key);
81+
if (person != null) {
82+
result.put(key, person);
83+
}
84+
}
85+
return result;
86+
}
87+
88+
@Override
89+
public Iterable<Integer> loadAllKeys() {
90+
log.info("JpaPersonMapStore::loadAllKeys");
91+
return this.personRepository.getAllIds();
92+
}
93+
94+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package sample.com.hazelcast.cloud.mapstore4.jpa;
2+
3+
import java.io.Serializable;
4+
import java.util.Objects;
5+
6+
import javax.persistence.Entity;
7+
import javax.persistence.Id;
8+
import javax.persistence.Table;
9+
10+
import lombok.AllArgsConstructor;
11+
import lombok.Builder;
12+
import lombok.Getter;
13+
import lombok.NoArgsConstructor;
14+
import lombok.Setter;
15+
import lombok.ToString;
16+
import org.hibernate.Hibernate;
17+
18+
@Getter
19+
@Setter
20+
@ToString
21+
@NoArgsConstructor
22+
@AllArgsConstructor
23+
@Builder
24+
@Entity
25+
@Table(name = "person")
26+
public class Person implements Serializable {
27+
28+
private static final long serialVersionUID = 1L;
29+
30+
@Id
31+
private Integer id;
32+
33+
private String name;
34+
35+
private String lastname;
36+
37+
@Override
38+
public boolean equals(Object o) {
39+
if (this == o) {
40+
return true;
41+
}
42+
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) {
43+
return false;
44+
}
45+
Person person = (Person) o;
46+
return id != null && Objects.equals(id, person.id);
47+
}
48+
49+
@Override
50+
public int hashCode() {
51+
return getClass().hashCode();
52+
}
53+
54+
}

0 commit comments

Comments
 (0)