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:
parent
4b19cb6bcc
commit
76673a33f1
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.hibernate;
|
||||
|
||||
public class UnsupportedTenancyException extends Exception {
|
||||
public UnsupportedTenancyException (String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue