First commmit for Spring Multi-tenancy with Hibernate example.
This commit is contained in:
parent
df2f1cbaf8
commit
ec712af5f0
|
@ -0,0 +1,19 @@
|
|||
package com.baeldung.multitenancy.entities;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Entity
|
||||
public class Book {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@Column(name = "id")
|
||||
Long id;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "name")
|
||||
String name;
|
||||
|
||||
// standard getters and setters
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.baeldung.multitenancy.implementation;
|
||||
|
||||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
/**
|
||||
* CurrentSessionTenantIdentifierResolver-- here we fetch the tenantId from the request.
|
||||
* User: baeldung
|
||||
* Date: 9/06/15
|
||||
*/
|
||||
|
||||
public class CurrentSessionTenantIdentifierResolver implements CurrentTenantIdentifierResolver {
|
||||
|
||||
@Autowired
|
||||
private HttpServletRequest request;
|
||||
|
||||
@Override
|
||||
public String resolveCurrentTenantIdentifier() {
|
||||
String tenantId = request.getHeader("X-TenantId");
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateExistingCurrentSessions() {
|
||||
// Additional logic to ensure appropriate connections are made.
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.baeldung.multitenancy.implementation;
|
||||
|
||||
import org.hibernate.tool.hbm2ddl.SchemaExport;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA.
|
||||
* User: vtajzich
|
||||
* Date: 8/21/13
|
||||
*/
|
||||
public class SessionFactoryBean extends org.springframework.orm.hibernate4.LocalSessionFactoryBean {
|
||||
|
||||
private Map<String, DataSource> dataSourceMap;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws IOException {
|
||||
super.afterPropertiesSet();
|
||||
|
||||
for (Map.Entry<String, DataSource> entry : dataSourceMap.entrySet()) {
|
||||
|
||||
Connection connection = null;
|
||||
|
||||
try {
|
||||
|
||||
connection = entry.getValue().getConnection();
|
||||
|
||||
SchemaExport export = new SchemaExport(getConfiguration(), connection);
|
||||
|
||||
export.setOutputFile(entry.getKey() + "-schema.sql");
|
||||
export.setDelimiter(";");
|
||||
|
||||
// define your rules, here.
|
||||
//The below code allows creation, but does not allow dropping entries
|
||||
export.execute(true, true, false, true);
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setDataSourceMap(Map<String, DataSource> dataSourceMap) {
|
||||
this.dataSourceMap = dataSourceMap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.multitenancy.implementation;
|
||||
|
||||
import org.hibernate.service.jdbc.connections.spi.AbstractDataSourceBasedMultiTenantConnectionProviderImpl;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* CurrentSessionTenantIdentifierResolver-- here we fetch the DB conection for the given tenantIdentifier.
|
||||
* User: baeldung
|
||||
* Date: 9/06/15
|
||||
*/
|
||||
|
||||
public class SimpleMultiTenantConnectionProvider extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {
|
||||
|
||||
private Map<String, DataSource> dataSourceMap;
|
||||
|
||||
@Override
|
||||
protected DataSource selectAnyDataSource() {
|
||||
return (DataSource) dataSourceMap.values().toArray()[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSource selectDataSource(String tenantIdentifier) {
|
||||
return dataSourceMap.get(tenantIdentifier);
|
||||
}
|
||||
|
||||
public Map<String, DataSource> getDataSourceMap() {
|
||||
return dataSourceMap;
|
||||
}
|
||||
|
||||
public void setDataSourceMap(Map<String, DataSource> dataSourceMap) {
|
||||
this.dataSourceMap = dataSourceMap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.baeldung.multitenancy.service;
|
||||
|
||||
import com.baeldung.multitenancy.entities.Book;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MultitenantService-- we use the SessionFactory to save and fetch entities.
|
||||
* User: baeldung
|
||||
* Date: 9/06/15
|
||||
*/
|
||||
|
||||
@Service
|
||||
public class MultiTenantService {
|
||||
|
||||
@AutoWired
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
public void save(Book book) {
|
||||
sessionFactory.getCurrentSession().save(book);
|
||||
}
|
||||
|
||||
public Book findBook(Long id) {
|
||||
return (Book) sessionFactory.
|
||||
getCurrentSession().get(Book.class, id);
|
||||
}
|
||||
|
||||
public List<Book> findAllBooks() {
|
||||
return sessionFactory.
|
||||
getCurrentSession().createQuery("from Books").list();
|
||||
}
|
||||
|
||||
public void setSessionFactory(SessionFactory sessionFactory){
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
|
||||
|
||||
<context:property-placeholder location="classpath*:database.properties" />
|
||||
<context:spring-configured />
|
||||
|
||||
<context:component-scan base-package="com.baeldung.multitenancy">
|
||||
</context:component-scan>
|
||||
|
||||
<util:map id="mydatasources">
|
||||
<entry key="tenant1" value-ref="source1" />
|
||||
<entry key="tenant2" value-ref="source2" />
|
||||
</util:map>
|
||||
|
||||
<bean id="source1" parent="mainDataSource">
|
||||
<property name="url" value="jdbc:mysql://localhost/tenant1" />
|
||||
<property name="username" value="baeldung" />
|
||||
<property name="password" value="spring" />
|
||||
</bean>
|
||||
|
||||
<bean id="source2" parent="mainDataSource">
|
||||
<property name="url" value="jdbc:mysql://localhost/tenant2" />
|
||||
<property name="username" value="testuser" />
|
||||
<property name="password" value="password" />
|
||||
</bean>
|
||||
|
||||
<bean class="org.apache.commons.dbcp.BasicDataSource" abstract="true"
|
||||
destroy-method="close" id="mainDataSource">
|
||||
<property name="driverClassName" value="${database.driverClassName}" />
|
||||
<property name="testOnBorrow" value="true" />
|
||||
<property name="testOnReturn" value="true" />
|
||||
<property name="testWhileIdle" value="true" />
|
||||
<property name="numTestsPerEvictionRun" value="2" />
|
||||
<property name="minEvictableIdleTimeMillis" value="1000000" />
|
||||
<property name="timeBetweenEvictionRunsMillis" value="1000000" />
|
||||
<property name="validationQuery" value="SELECT 1" />
|
||||
</bean>
|
||||
|
||||
<bean id="sessionFactory" class="com.baeldung.multitenancy.SessionFactoryBean">
|
||||
<property name="dataSourceMap" ref="mydatasources" />
|
||||
<property name="dataSource" ref="source1" />
|
||||
<property name="hibernateProperties">
|
||||
<map>
|
||||
<entry key="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
|
||||
<entry key="hibernate.show_sql" value="true" />
|
||||
<entry key="hibernate.multiTenancy" value="DATABASE" />
|
||||
<entry key="hibernate.tenant_identifier_resolver"
|
||||
value-ref="currentSessionTenantIdentifierResolver" />
|
||||
<entry key="hibernate.multi_tenant_connection_provider"
|
||||
value-ref="simpleMultiTenantConnectionProvider" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="currentSessionTenantIdentifierResolver"
|
||||
class="com.baeldung.multitenancy.implementation.CurrentSessionTenantIdentifierResolver"
|
||||
scope="request">
|
||||
<aop:scoped-proxy />
|
||||
</bean>
|
||||
|
||||
<bean id="simpleMultiTenantConnectionProvider"
|
||||
class="com.baeldung.multitenancy.implementation.SimpleMultiTenantConnectionProvider">
|
||||
<property name="dataSourceMap" ref="datasources" />
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="multitenantService" class="com.baeldung.multitenancy.service.MultitenantService">
|
||||
<property name="sessionFactory" ref="sessionFactory" />
|
||||
</bean>
|
||||
|
||||
<tx:annotation-driven mode="aspectj"
|
||||
transaction-manager="transactionManager" />
|
||||
|
||||
<bean id="transactionManager"
|
||||
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
|
||||
<property name="sessionFactory" ref="sessionFactory" />
|
||||
<property name="autodetectDataSource" value="false" />
|
||||
</bean>
|
||||
|
||||
<tx:advice id="transactionServiceDao" transaction-manager="transactionManager">
|
||||
<tx:attributes>
|
||||
<tx:method name="exists" propagation="SUPPORTS"
|
||||
rollback-for="java.lang.Exception" />
|
||||
<tx:method name="find*" propagation="SUPPORTS"
|
||||
rollback-for="java.lang.Exception" />
|
||||
<tx:method name="get*" propagation="SUPPORTS"
|
||||
rollback-for="java.lang.Exception" />
|
||||
<tx:method name="*" propagation="REQUIRED"
|
||||
rollback-for="java.lang.Exception" />
|
||||
<tx:method name="*Commit" propagation="REQUIRES_NEW"
|
||||
rollback-for="java.lang.Exception" />
|
||||
</tx:attributes>
|
||||
</tx:advice>
|
||||
|
||||
<aop:config>
|
||||
<aop:pointcut id="serviceInvocation"
|
||||
expression="execution(public com.baeldung.multitenancy.service.MultitenantService.*(..))" />
|
||||
<aop:advisor pointcut-ref="serviceInvocation"
|
||||
advice-ref="transactionServiceDao" />
|
||||
</aop:config>
|
||||
|
||||
</beans>
|
|
@ -0,0 +1 @@
|
|||
database.driverClassName=com.mysql.jdbc.Driver
|
Loading…
Reference in New Issue