Skip to content

Commit 2a8e42f

Browse files
rajangareyuce
andauthored
Hazelcast integration with Hikari connection pool (#694)
Hazelcast Integration with Hikari Connection Pool To create Hikari connection pool, first create database table mapping with Hazelcast in-memory map. In this demo, I have used EMPLOYEE table created on H2 DB, which is mapped with employee-map. - Create Hikari data source from HikariConfig, with database credentials and connection pool configuration e.g. pool size, connection timeout etc. - Get the connection from Hikari Data Source. - Implement the Map Store Factory from MapLoader<K, V>, MapStore<K, V> and override all the necessary methods. - Register the MapStore into hazelcast.xml config. <hazelcast> ... <map name="empaloyee_map"> <map-store enabled="true"> <class-name>com.demo.maps.EmployeeMapStore</class-name> </map-store> </map> ... </hazelcast> Database connection information can be externalized from hazelcast.xml. Build the above classes in a jar and copy them inside Hazelcast user-lib directory under the Hazelcast installation. --------- Co-authored-by: Yüce Tekol <[email protected]>
1 parent 0b0a0f2 commit 2a8e42f

File tree

9 files changed

+290
-0
lines changed

9 files changed

+290
-0
lines changed

hazelcast-integration/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@
2525
Implementation of integration of MongoDB with hazelcast.
2626
- <h3>openshift</h3>
2727
A guideline to start using Hazelcast on the Red Hat OpenShift platform.
28+
- <h3>hikari-connection-pool</h3>
29+
A sample demo code integrate Hazelcast with Hikari connection pool.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<h1>Hazelcast Integration with Hikari Connection Pool</h1>
2+
To create Hikari connection pool, first create database table mapping with Hazelcast in-memory map.
3+
In this demo, I have used EMPLOYEE table created on H2 DB, which is mapped with employee-map.
4+
5+
- Create Hikari data source from HikariConfig, with database credentials and connection pool configuration e.g. pool size, connection timeout etc.
6+
- Get the connection from Hikari Data Source.
7+
- Implement the Map Store Factory from MapLoader<K, V>, MapStore<K, V> and override all the necessary methods.
8+
- Register the MapStore into hazelcast.xml config.
9+
10+
11+
<hazelcast>
12+
...
13+
<map name="empaloyee_map">
14+
<map-store enabled="true">
15+
<class-name>com.demo.maps.EmployeeMapStore</class-name>
16+
</map-store>
17+
</map>
18+
...
19+
</hazelcast>
20+
21+
Database connection information can be externalized from hazelcast.xml. Build the above classes in a jar and copy them inside hazelcast user-lib directory under the Hazelcast installation.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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+
<packaging>jar</packaging>
7+
<parent>
8+
<groupId>com.hazelcast.samples</groupId>
9+
<artifactId>hazelcast-integration</artifactId>
10+
<version>0.1-SNAPSHOT</version>
11+
</parent>
12+
13+
<artifactId>hikari-connection-pool</artifactId>
14+
<name>Hazelcast Hikari Connection Pool</name>
15+
<description>A sample demo code to integrate Hazelcast with Hikari connection pool</description>
16+
17+
<properties>
18+
<main.basedir>${project.parent.parent.basedir}</main.basedir>
19+
20+
<maven.compiler.source>17</maven.compiler.source>
21+
<maven.compiler.target>17</maven.compiler.target>
22+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23+
</properties>
24+
25+
<dependencies>
26+
<dependency>
27+
<groupId>com.hazelcast</groupId>
28+
<artifactId>hazelcast</artifactId>
29+
<version>${hazelcast.version}</version>
30+
<scope>provided</scope>
31+
</dependency>
32+
33+
<dependency>
34+
<groupId>com.h2database</groupId>
35+
<artifactId>h2</artifactId>
36+
<version>2.2.224</version>
37+
<scope>test</scope>
38+
</dependency>
39+
</dependencies>
40+
</project>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.hazelcast.samples.connection;
2+
3+
import java.sql.DriverManager;
4+
import java.sql.SQLException;
5+
6+
public class JDBCBasicConnection {
7+
public static void getConnection() {
8+
try {
9+
Class.forName("org.h2.Driver");
10+
DriverManager.getConnection("jdbc:h2:~/test", "sa", "");
11+
} catch (ClassNotFoundException | SQLException e) {
12+
throw new RuntimeException(e);
13+
}
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.hazelcast.samples.connection.pool;
2+
3+
import com.hazelcast.shaded.com.zaxxer.hikari.HikariConfig;
4+
import com.hazelcast.shaded.com.zaxxer.hikari.HikariDataSource;
5+
6+
import java.sql.Connection;
7+
import java.sql.SQLException;
8+
9+
/**
10+
* Connection pool data source class
11+
* Implement this class as thread-safe in multithreading environment
12+
*/
13+
public class HikariDataSourcePool {
14+
private static HikariDataSource hikariDataSource = null;
15+
private static final HikariDataSourcePool hikariDataSourcePool = null;
16+
17+
private HikariDataSourcePool() {
18+
if (null != hikariDataSource) {
19+
System.out.println("Hikari data source already created. existing connection can be used.");
20+
} else {
21+
createHikariDataSource();
22+
}
23+
}
24+
25+
private void createHikariDataSource() {
26+
HikariConfig hikariConfig = new HikariConfig();
27+
28+
hikariConfig.setJdbcUrl("jdbc:h2:mem:testdb");
29+
hikariConfig.setUsername("sa");
30+
hikariConfig.setPassword("");
31+
hikariConfig.setMaximumPoolSize(5);
32+
hikariConfig.setIdleTimeout(30000);
33+
hikariConfig.setConnectionTimeout(30000);
34+
hikariConfig.setPoolName("Demo-POOL");
35+
hikariConfig.setDriverClassName("org.h2.Driver");
36+
37+
hikariDataSource = new HikariDataSource(hikariConfig);
38+
39+
System.out.println("Datasource Created..");
40+
}
41+
42+
/**
43+
*
44+
* Implementation should be thread-safe
45+
*/
46+
public static synchronized Connection getConnection() {
47+
try {
48+
if (null != hikariDataSource) {
49+
System.err.println("\nGetting....! SQL Connection from HIKARI POOL.\n");
50+
return hikariDataSource.getConnection();
51+
} else {
52+
throw new RuntimeException("Ops! Hikari datasource not available.");
53+
}
54+
} catch (SQLException exception) {
55+
throw new RuntimeException("Exception while creating database connection." + exception);
56+
}
57+
}
58+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package com.hazelcast.samples.map;
2+
3+
import com.hazelcast.map.MapLoader;
4+
import com.hazelcast.map.MapStore;
5+
import com.hazelcast.samples.model.Employee;
6+
7+
import java.sql.*;
8+
import java.util.ArrayList;
9+
import java.util.Collection;
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.stream.Collectors;
13+
14+
import static com.hazelcast.samples.connection.pool.HikariDataSourcePool.getConnection;
15+
16+
public class EmployeeMapStore implements MapLoader<Integer, Employee>, MapStore<Integer, Employee> {
17+
18+
public EmployeeMapStore() {
19+
}
20+
21+
@Override
22+
public Iterable<Integer> loadAllKeys() {
23+
String query = "SELECT EMPID FROM EMPLOYEE";
24+
25+
List<Integer> empIds = new ArrayList<>();
26+
try (Connection connection = getConnection();
27+
PreparedStatement preparedStatement = connection.prepareStatement(query);
28+
ResultSet resultSet = preparedStatement.executeQuery()) {
29+
while (resultSet.next()) {
30+
empIds.add(resultSet.getInt(1));
31+
}
32+
} catch (SQLException exception) {
33+
throw new RuntimeException("Error on load all keys : " + exception);
34+
}
35+
36+
return empIds;
37+
}
38+
39+
@Override
40+
public Employee load(Integer empId) {
41+
String query = "SELECT EMPID, NAME, SALARY FROM EMPLOYEE WHERE EMPID=?";
42+
Employee employee = null;
43+
try (Connection connection = getConnection();
44+
PreparedStatement preparedStatement = connection.prepareStatement(query)) {
45+
preparedStatement.setInt(1, empId);
46+
ResultSet resultSet = preparedStatement.executeQuery();
47+
48+
if (resultSet.next()) {
49+
employee = new Employee(resultSet.getInt(1), resultSet.getString(2), resultSet.getDouble(3));
50+
}
51+
} catch (SQLException exception) {
52+
throw new RuntimeException("Error on load key : " + exception);
53+
}
54+
55+
return employee;
56+
}
57+
58+
@Override
59+
public Map<Integer, String> loadAll(Collection collection) {
60+
System.out.println("Load all employee..");
61+
62+
List<Integer> employees = (List<Integer>) collection;
63+
64+
return employees.stream().collect(Collectors.toMap(id -> id, id -> load(id).toString()));
65+
}
66+
67+
@Override
68+
public void store(Integer integer, Employee employee) {
69+
String storeQuery = "INSERT INTO EMPLOYEE(EMPID, NAME, SALARY) VALUES(?, ?, ?)";
70+
try (Connection connection = getConnection();
71+
PreparedStatement preparedStatement = connection.prepareStatement(storeQuery)) {
72+
preparedStatement.setInt(1, employee.empId());
73+
preparedStatement.setString(2, employee.name());
74+
preparedStatement.setDouble(3, employee.salary());
75+
76+
preparedStatement.executeUpdate();
77+
} catch (Exception exception) {
78+
System.out.println("Exception : " + exception.getMessage());
79+
throw new RuntimeException(exception.getMessage());
80+
}
81+
}
82+
83+
84+
@Override
85+
public void storeAll(Map<Integer, Employee> map) {
86+
String storeQuery = "INSERT INTO EMPLOYEE(EMPID, NAME, SALARY) VALUES(?, ?, ?)";
87+
try (Connection connection = getConnection();
88+
PreparedStatement preparedStatement = connection.prepareStatement(storeQuery)) {
89+
map.forEach((identity, employee) -> {
90+
91+
try {
92+
preparedStatement.setInt(1, employee.empId());
93+
preparedStatement.setString(2, employee.name());
94+
preparedStatement.setDouble(3, employee.salary());
95+
preparedStatement.addBatch();
96+
} catch (SQLException e) {
97+
throw new RuntimeException(e);
98+
}
99+
});
100+
101+
int[] batchResults = preparedStatement.executeBatch();
102+
} catch (SQLException exception) {
103+
System.out.println("Exception : " + exception.getMessage());
104+
throw new RuntimeException(exception.getMessage());
105+
}
106+
}
107+
108+
@Override
109+
public void delete(Integer empId) {
110+
String deleteQuery = "DELETE FROM EMPLOYEE WHERE EMPID=?";
111+
try (Connection connection = getConnection();
112+
PreparedStatement preparedStatement = connection.prepareStatement(deleteQuery)) {
113+
preparedStatement.setInt(1, empId);
114+
115+
preparedStatement.executeUpdate();
116+
} catch (Exception exception) {
117+
System.out.println("Exception : " + exception.getMessage());
118+
throw new RuntimeException(exception.getMessage());
119+
}
120+
}
121+
122+
@Override
123+
public void deleteAll(Collection<Integer> empIds) {
124+
String deleteQuery = "DELETE FROM EMPLOYEE WHERE EMPID IN (?)";
125+
try (Connection connection = getConnection();
126+
PreparedStatement preparedStatement = connection.prepareStatement(deleteQuery)) {
127+
Array empIdsInArray = connection.createArrayOf("integer", empIds.toArray());
128+
preparedStatement.setArray(1, empIdsInArray);
129+
130+
preparedStatement.executeUpdate();
131+
} catch (Exception exception) {
132+
System.out.println("Exception : " + exception.getMessage());
133+
throw new RuntimeException(exception.getMessage());
134+
}
135+
}
136+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.hazelcast.samples.model;
2+
3+
public record Employee(Integer empId, String name, Double salary) {
4+
5+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<hazelcast>
3+
4+
<!--Sample map config XML-->
5+
<map name="empaloyee_map">
6+
<map-store enabled="true">
7+
<class-name>com.demo.maps.EmployeeMapStore</class-name>
8+
</map-store>
9+
</map>
10+
11+
</hazelcast>
12+

hazelcast-integration/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
<module>manager-based-session-replication</module>
4747
<module>openshift</module>
4848
<module>eureka</module>
49+
<module>hikari-connection-pool</module>
4950
</modules>
5051

5152
<dependencies>

0 commit comments

Comments
 (0)