Hibernate 5 Multitenancy tutorial (#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...
This commit is contained in:
Parth Joshi 2017-04-20 18:25:34 +05:30 committed by KevinGilmore
parent 4b19cb6bcc
commit 76673a33f1
10 changed files with 416 additions and 2 deletions

62
hibernate5/pom.xml Normal file
View File

@ -0,0 +1,62 @@
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>com.baeldung</groupId>
<artifactId>hibernate5</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>hibernate5</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Maven plugins -->
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.9.Final</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.194</version>
</dependency>
</dependencies>
<build>
<finalName>hibernate5</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,30 @@
package com.baeldung.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.baeldung.hibernate.pojo.Supplier;
/**
* Hello world!
*
*/
public class App {
public static void main(String[] args) {
try {
// NOTE: this is just for boostrap testing for multitenancy.
System.out.println("Checking the system.");
SessionFactory sessionFactory = HibernateMultiTenantUtil.getSessionFactory();
Session currentSession = sessionFactory.withOptions().tenantIdentifier("h2db1").openSession();
Transaction transaction = currentSession.getTransaction();
transaction.begin();
currentSession.createCriteria(Supplier.class).list().stream().forEach(System.out::println);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,41 @@
package com.baeldung.hibernate;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
public class ConfigurableMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider {
private final Map<String, ConnectionProvider> connectionProviderMap =
new HashMap<>();
public ConfigurableMultiTenantConnectionProvider(
Map<String, ConnectionProvider> connectionProviderMap) {
this.connectionProviderMap.putAll( connectionProviderMap );
}
@Override
protected ConnectionProvider getAnyConnectionProvider() {
System.out.println("Any");
return connectionProviderMap.values().iterator().next();
}
@Override
protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
System.out.println("Specific");
return connectionProviderMap.get( tenantIdentifier );
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
Connection connection = super.getConnection(tenantIdentifier);
// uncomment to see option 2 for SCHEMA strategy.
//connection.createStatement().execute("SET SCHEMA '" + tenantIdentifier + "'");
return connection;
}
}

View File

@ -0,0 +1,95 @@
package com.baeldung.hibernate;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.ServiceRegistry;
import com.baeldung.hibernate.pojo.Supplier;
public class HibernateMultiTenantUtil {
private static SessionFactory sessionFactory;
private static Map<String, ConnectionProvider> connectionProviderMap = new HashMap<>();
private static final String[] tenantDBNames = { "mydb1","mydb2"};
public static SessionFactory getSessionFactory() throws UnsupportedTenancyException {
if (sessionFactory == null) {
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = configureServiceRegistry(configuration);
sessionFactory = makeSessionFactory (serviceRegistry);
// sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}
return sessionFactory;
}
private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) {
MetadataSources metadataSources = new MetadataSources( serviceRegistry );
for(Class annotatedClasses : getAnnotatedClasses()) {
metadataSources.addAnnotatedClass( annotatedClasses );
}
Metadata metadata = metadataSources.buildMetadata();
return metadata.getSessionFactoryBuilder().build();
}
private static Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Supplier.class
};
}
private static ServiceRegistry configureServiceRegistry(Configuration configuration) throws UnsupportedTenancyException {
Properties properties = configuration.getProperties();
connectionProviderMap = setUpConnectionProviders(properties, tenantDBNames);
properties.put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, new ConfigurableMultiTenantConnectionProvider(connectionProviderMap));
return new StandardServiceRegistryBuilder().applySettings(properties).build();
}
private static Map<String, ConnectionProvider> setUpConnectionProviders(Properties properties, String[] tenantNames) throws UnsupportedTenancyException {
Map<String, ConnectionProvider> providerMap = new HashMap<>();
for (String tenant : tenantNames) {
DriverManagerConnectionProviderImpl connectionProvider = new DriverManagerConnectionProviderImpl();
String tenantStrategy = properties.getProperty("hibernate.multiTenancy");
System.out.println("Strategy:"+tenantStrategy);
properties.put(Environment.URL, tenantUrl(properties.getProperty(Environment.URL), tenant, tenantStrategy));
System.out.println("URL:"+properties.getProperty(Environment.URL));
connectionProvider.configure(properties);
System.out.println("Tenant:"+tenant);
providerMap.put(tenant, connectionProvider);
}
System.out.println("Added connections for:");
providerMap.keySet().stream().forEach(System.out::println);
return providerMap;
}
private static Object tenantUrl(String originalUrl, String tenant, String tenantStrategy) throws UnsupportedTenancyException {
if (tenantStrategy.toUpperCase().equals("DATABASE")) {
return originalUrl.replace(DEFAULT_DB_NAME, tenant);
} else if (tenantStrategy.toUpperCase().equals("SCHEMA")) {
return originalUrl + String.format(SCHEMA_TOKEN, tenant);
} else {
throw new UnsupportedTenancyException("Not yet supported");
}
}
public static final String SCHEMA_TOKEN = ";INIT=CREATE SCHEMA IF NOT EXISTS %1$s\\;SET SCHEMA %1$s";
public static final String DEFAULT_DB_NAME = "mydb1";
}

View File

@ -0,0 +1,24 @@
package com.baeldung.hibernate;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
Configuration configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}

View File

@ -0,0 +1,8 @@
package com.baeldung.hibernate;
public class UnsupportedTenancyException extends Exception {
public UnsupportedTenancyException (String message) {
super(message);
}
}

View File

@ -0,0 +1,67 @@
package com.baeldung.hibernate.pojo;
// Generated Feb 9, 2017 11:31:36 AM by Hibernate Tools 5.1.0.Final
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.junit.runners.Suite.SuiteClasses;
/**
* Suppliers generated by hbm2java
*/
@Entity(name = "Supplier")
@Table(name ="Supplier")
public class Supplier implements java.io.Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String country;
public Supplier() {
}
public Supplier(String name, String country) {
this.name = name;
this.country = country;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getCountry() {
return this.country;
}
public void setCountry(String country) {
this.country = country;
}
@Override
public String toString() {
return new StringBuffer().append("[").append(id).append(",").append(name).append(",").append(country).append("]").toString();
}
@Override
public boolean equals(Object obj) {
return name.equals(((Supplier) obj).getName());
}
}

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">org.h2.Driver</property>
<property name="hibernate.connection.url">jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1</property>
<property name="hibernate.connection.username">sa</property>
<property name="connection.password"/>
<property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
<property name="hibernate.multiTenancy">DATABASE</property>
</session-factory>
</hibernate-configuration>

View File

@ -0,0 +1,73 @@
package com.baeldung.hibernate;
import static org.junit.Assert.assertNotEquals;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.hibernate.pojo.Supplier;
public class MultiTenantHibernateTest {
@Test
public void givenDBMode_whenFetchingSuppliers_thenComparingFromDbs () {
SessionFactory sessionFactory;
try {
sessionFactory = HibernateMultiTenantUtil.getSessionFactory();
Session db1Session = sessionFactory
.withOptions().tenantIdentifier("mydb1").openSession();
initDb1(db1Session);
Transaction transaction = db1Session.getTransaction();
transaction.begin();
Supplier supplierFromDB1 = (Supplier)db1Session.createCriteria(Supplier.class).list().get(0);
transaction.commit();
Session db2Session = sessionFactory
.withOptions().tenantIdentifier("mydb2").openSession();
initDb2(db2Session);
db2Session.getTransaction().begin();
Supplier supplierFromDB2 = (Supplier) db2Session.createCriteria(Supplier.class).list().get(0);
db2Session.getTransaction().commit();
System.out.println(supplierFromDB1);
System.out.println(supplierFromDB2);
assertNotEquals(supplierFromDB1, supplierFromDB2);
} catch (UnsupportedTenancyException e) {
e.printStackTrace();
}
}
private void initDb1(Session db1Session) {
System.out.println("Init DB1");
Transaction transaction = db1Session.getTransaction();
transaction.begin();
db1Session.createSQLQuery("DROP ALL OBJECTS").executeUpdate();
db1Session.createSQLQuery("create table Supplier (id integer generated by default as identity, country varchar(255), name varchar(255), primary key (id))").executeUpdate();
db1Session.createSQLQuery("insert into Supplier (id, country, name) values (null, 'John', 'USA')").executeUpdate();
transaction.commit();
}
private void initDb2(Session db2Session) {
System.out.println("Init DB2");
Transaction transaction = db2Session.getTransaction();
transaction.begin();
db2Session.createSQLQuery("DROP ALL OBJECTS").executeUpdate();
db2Session.createSQLQuery("create table Supplier (id integer generated by default as identity, country varchar(255), name varchar(255), primary key (id))").executeUpdate();
db2Session.createSQLQuery("insert into Supplier (id, country, name) values (null, 'Miller', 'UK')").executeUpdate();
transaction.commit();
}
}

View File

@ -226,7 +226,7 @@
<version>1.6.0</version>
<configuration>
<executable>maven</executable>
<module>hibernate5</module>
</configuration>
</plugin>