Skip to content

Commit 76673a3

Browse files
joshiparthinKevinGilmore
authored andcommitted
Hibernate 5 Multitenancy tutorial (eugenp#1150)
* First commit for Hibernate 5 Multitenancy tutorial * Changes to fix the code. * Added hibernate begin transaction code. * Changes to solve the multitenancy issue. * Changes to integrate h2 * Changing configs to solve the error * Changes to solve h2 error... * Changes to fix H2 error. * Cleaned POM.xml and changed entity name * Changes table name to supplier * Removed MySql Dep from pom.xml. * Changes as per comment in the PR...
1 parent 4b19cb6 commit 76673a3

File tree

10 files changed

+416
-2
lines changed

10 files changed

+416
-2
lines changed

hibernate5/pom.xml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?xml version="1.0"?>
2+
<project
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
4+
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>com.baeldung</groupId>
8+
<artifactId>parent-modules</artifactId>
9+
<version>1.0.0-SNAPSHOT</version>
10+
</parent>
11+
<groupId>com.baeldung</groupId>
12+
<artifactId>hibernate5</artifactId>
13+
<version>0.0.1-SNAPSHOT</version>
14+
<name>hibernate5</name>
15+
<url>http://maven.apache.org</url>
16+
<properties>
17+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
18+
<!-- Maven plugins -->
19+
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
20+
</properties>
21+
<dependencies>
22+
<dependency>
23+
<groupId>org.hibernate</groupId>
24+
<artifactId>hibernate-core</artifactId>
25+
<version>5.2.9.Final</version>
26+
</dependency>
27+
<dependency>
28+
<groupId>junit</groupId>
29+
<artifactId>junit</artifactId>
30+
<version>4.12</version>
31+
</dependency>
32+
<dependency>
33+
<groupId>com.h2database</groupId>
34+
<artifactId>h2</artifactId>
35+
<version>1.4.194</version>
36+
</dependency>
37+
</dependencies>
38+
<build>
39+
<finalName>hibernate5</finalName>
40+
<resources>
41+
<resource>
42+
<directory>src/main/resources</directory>
43+
<filtering>true</filtering>
44+
</resource>
45+
</resources>
46+
47+
<plugins>
48+
<plugin>
49+
<groupId>org.apache.maven.plugins</groupId>
50+
<artifactId>maven-compiler-plugin</artifactId>
51+
<version>${maven-compiler-plugin.version}</version>
52+
<configuration>
53+
<source>1.8</source>
54+
<target>1.8</target>
55+
</configuration>
56+
</plugin>
57+
58+
</plugins>
59+
60+
</build>
61+
62+
</project>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.baeldung.hibernate;
2+
3+
import org.hibernate.Session;
4+
import org.hibernate.SessionFactory;
5+
import org.hibernate.Transaction;
6+
7+
import com.baeldung.hibernate.pojo.Supplier;
8+
9+
/**
10+
* Hello world!
11+
*
12+
*/
13+
public class App {
14+
public static void main(String[] args) {
15+
try {
16+
// NOTE: this is just for boostrap testing for multitenancy.
17+
System.out.println("Checking the system.");
18+
SessionFactory sessionFactory = HibernateMultiTenantUtil.getSessionFactory();
19+
Session currentSession = sessionFactory.withOptions().tenantIdentifier("h2db1").openSession();
20+
Transaction transaction = currentSession.getTransaction();
21+
transaction.begin();
22+
currentSession.createCriteria(Supplier.class).list().stream().forEach(System.out::println);
23+
transaction.commit();
24+
25+
} catch (Exception e) {
26+
e.printStackTrace();
27+
}
28+
29+
}
30+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.baeldung.hibernate;
2+
3+
import java.sql.Connection;
4+
import java.sql.SQLException;
5+
import java.util.HashMap;
6+
import java.util.Map;
7+
8+
import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider;
9+
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
10+
11+
public class ConfigurableMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider {
12+
13+
private final Map<String, ConnectionProvider> connectionProviderMap =
14+
new HashMap<>();
15+
16+
17+
public ConfigurableMultiTenantConnectionProvider(
18+
Map<String, ConnectionProvider> connectionProviderMap) {
19+
this.connectionProviderMap.putAll( connectionProviderMap );
20+
}
21+
@Override
22+
protected ConnectionProvider getAnyConnectionProvider() {
23+
System.out.println("Any");
24+
return connectionProviderMap.values().iterator().next();
25+
}
26+
27+
@Override
28+
protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
29+
System.out.println("Specific");
30+
return connectionProviderMap.get( tenantIdentifier );
31+
}
32+
33+
@Override
34+
public Connection getConnection(String tenantIdentifier) throws SQLException {
35+
Connection connection = super.getConnection(tenantIdentifier);
36+
// uncomment to see option 2 for SCHEMA strategy.
37+
//connection.createStatement().execute("SET SCHEMA '" + tenantIdentifier + "'");
38+
return connection;
39+
}
40+
41+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.baeldung.hibernate;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
import java.util.Properties;
6+
7+
import org.hibernate.SessionFactory;
8+
import org.hibernate.boot.Metadata;
9+
import org.hibernate.boot.MetadataSources;
10+
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
11+
import org.hibernate.cfg.AvailableSettings;
12+
import org.hibernate.cfg.Configuration;
13+
import org.hibernate.cfg.Environment;
14+
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
15+
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
16+
import org.hibernate.service.ServiceRegistry;
17+
18+
import com.baeldung.hibernate.pojo.Supplier;
19+
20+
public class HibernateMultiTenantUtil {
21+
private static SessionFactory sessionFactory;
22+
private static Map<String, ConnectionProvider> connectionProviderMap = new HashMap<>();
23+
private static final String[] tenantDBNames = { "mydb1","mydb2"};
24+
25+
public static SessionFactory getSessionFactory() throws UnsupportedTenancyException {
26+
if (sessionFactory == null) {
27+
Configuration configuration = new Configuration().configure();
28+
ServiceRegistry serviceRegistry = configureServiceRegistry(configuration);
29+
sessionFactory = makeSessionFactory (serviceRegistry);
30+
// sessionFactory = configuration.buildSessionFactory(serviceRegistry);
31+
32+
33+
}
34+
return sessionFactory;
35+
}
36+
37+
private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) {
38+
MetadataSources metadataSources = new MetadataSources( serviceRegistry );
39+
for(Class annotatedClasses : getAnnotatedClasses()) {
40+
metadataSources.addAnnotatedClass( annotatedClasses );
41+
}
42+
43+
Metadata metadata = metadataSources.buildMetadata();
44+
return metadata.getSessionFactoryBuilder().build();
45+
46+
}
47+
48+
private static Class<?>[] getAnnotatedClasses() {
49+
return new Class<?>[] {
50+
Supplier.class
51+
};
52+
}
53+
54+
private static ServiceRegistry configureServiceRegistry(Configuration configuration) throws UnsupportedTenancyException {
55+
Properties properties = configuration.getProperties();
56+
57+
connectionProviderMap = setUpConnectionProviders(properties, tenantDBNames);
58+
properties.put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, new ConfigurableMultiTenantConnectionProvider(connectionProviderMap));
59+
60+
return new StandardServiceRegistryBuilder().applySettings(properties).build();
61+
}
62+
63+
private static Map<String, ConnectionProvider> setUpConnectionProviders(Properties properties, String[] tenantNames) throws UnsupportedTenancyException {
64+
Map<String, ConnectionProvider> providerMap = new HashMap<>();
65+
for (String tenant : tenantNames) {
66+
DriverManagerConnectionProviderImpl connectionProvider = new DriverManagerConnectionProviderImpl();
67+
68+
String tenantStrategy = properties.getProperty("hibernate.multiTenancy");
69+
System.out.println("Strategy:"+tenantStrategy);
70+
properties.put(Environment.URL, tenantUrl(properties.getProperty(Environment.URL), tenant, tenantStrategy));
71+
System.out.println("URL:"+properties.getProperty(Environment.URL));
72+
connectionProvider.configure(properties);
73+
System.out.println("Tenant:"+tenant);
74+
providerMap.put(tenant, connectionProvider);
75+
76+
}
77+
System.out.println("Added connections for:");
78+
providerMap.keySet().stream().forEach(System.out::println);
79+
return providerMap;
80+
}
81+
82+
private static Object tenantUrl(String originalUrl, String tenant, String tenantStrategy) throws UnsupportedTenancyException {
83+
if (tenantStrategy.toUpperCase().equals("DATABASE")) {
84+
return originalUrl.replace(DEFAULT_DB_NAME, tenant);
85+
} else if (tenantStrategy.toUpperCase().equals("SCHEMA")) {
86+
return originalUrl + String.format(SCHEMA_TOKEN, tenant);
87+
} else {
88+
throw new UnsupportedTenancyException("Not yet supported");
89+
}
90+
}
91+
92+
public static final String SCHEMA_TOKEN = ";INIT=CREATE SCHEMA IF NOT EXISTS %1$s\\;SET SCHEMA %1$s";
93+
public static final String DEFAULT_DB_NAME = "mydb1";
94+
95+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.baeldung.hibernate;
2+
3+
import org.hibernate.SessionFactory;
4+
import org.hibernate.cfg.Configuration;
5+
6+
public class HibernateUtil {
7+
8+
private static final SessionFactory sessionFactory;
9+
10+
static {
11+
try {
12+
Configuration configuration = new Configuration().configure();
13+
sessionFactory = configuration.buildSessionFactory();
14+
15+
} catch (Throwable ex) {
16+
System.err.println("Initial SessionFactory creation failed." + ex);
17+
throw new ExceptionInInitializerError(ex);
18+
}
19+
}
20+
21+
public static SessionFactory getSessionFactory() {
22+
return sessionFactory;
23+
}
24+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.baeldung.hibernate;
2+
3+
public class UnsupportedTenancyException extends Exception {
4+
public UnsupportedTenancyException (String message) {
5+
super(message);
6+
}
7+
8+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.baeldung.hibernate.pojo;
2+
// Generated Feb 9, 2017 11:31:36 AM by Hibernate Tools 5.1.0.Final
3+
4+
import javax.persistence.Entity;
5+
import javax.persistence.GeneratedValue;
6+
import javax.persistence.GenerationType;
7+
import javax.persistence.Id;
8+
import javax.persistence.Table;
9+
10+
import org.junit.runners.Suite.SuiteClasses;
11+
12+
13+
/**
14+
* Suppliers generated by hbm2java
15+
*/
16+
@Entity(name = "Supplier")
17+
@Table(name ="Supplier")
18+
public class Supplier implements java.io.Serializable {
19+
20+
@Id
21+
@GeneratedValue(strategy = GenerationType.IDENTITY)
22+
private Integer id;
23+
private String name;
24+
private String country;
25+
26+
public Supplier() {
27+
}
28+
29+
public Supplier(String name, String country) {
30+
this.name = name;
31+
this.country = country;
32+
}
33+
34+
public Integer getId() {
35+
return this.id;
36+
}
37+
38+
public void setId(Integer id) {
39+
this.id = id;
40+
}
41+
42+
public String getName() {
43+
return this.name;
44+
}
45+
46+
public void setName(String name) {
47+
this.name = name;
48+
}
49+
50+
public String getCountry() {
51+
return this.country;
52+
}
53+
54+
public void setCountry(String country) {
55+
this.country = country;
56+
}
57+
58+
@Override
59+
public String toString() {
60+
return new StringBuffer().append("[").append(id).append(",").append(name).append(",").append(country).append("]").toString();
61+
}
62+
63+
@Override
64+
public boolean equals(Object obj) {
65+
return name.equals(((Supplier) obj).getName());
66+
}
67+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE hibernate-configuration PUBLIC
3+
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
4+
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
5+
<hibernate-configuration>
6+
<session-factory>
7+
<property name="hibernate.connection.driver_class">org.h2.Driver</property>
8+
<property name="hibernate.connection.url">jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1</property>
9+
<property name="hibernate.connection.username">sa</property>
10+
<property name="connection.password"/>
11+
<property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
12+
<property name="hibernate.multiTenancy">DATABASE</property>
13+
</session-factory>
14+
</hibernate-configuration>

0 commit comments

Comments
 (0)