multi-tenancy can be achieved as you required by following steps.
- Add 2 configuration classes one for shared database and one for tenant database, which configurs LocalContainerEntityManagerFactoryBean. This bean should set the required multitenancy properties for LocalContainerEntityManagerFactoryBean
e.g.
Map<String, Object> properties = hibernateProperties.determineHibernateProperties(
this.properties.getProperties(), new HibernateSettings());
properties.put(Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
properties.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, this.connectionProvider);
properties.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, this.resolver);
properties.put(Environment.DIALECT, "org.hibernate.dialect.MySQLDialect");
This class should also implement named bean transactionManager for each type. e.g.
@Bean(name = "tenantTransactionManager")
public PlatformTransactionManager transactionManager() {
JpaTransactionManager tm = new JpaTransactionManager();
tm.setEntityManagerFactory(this.entityManagerFactory().getObject());
return tm;
}
implement interface CurrentTenantIdentifierResolver and method resolveCurrentTenantIdentifier. This should return the database name of the tenant based on the current logged-in user. Or default database name if no user is logged-in
A thread safe context holder to remember the current tenant name
Annotate the services implementations for the entity classes with @Transactional annotation and pass the bean name of appropriate entity manager e.g.
@Transactional("tenantTransactionManager") // for tenant database
and
@Transactional("transactionManager") // for shared database.
Setup a database schema creation method when a new users signs up. and maintain the tenant database name as one of the column in user table in shared schema.
If you are using spring security, implement UserDetailsService interface and implement method loadUserByUsername such that it returns an object of TenantUser class which contains additional information ( tenant database name) for the user logging in.
public class TenantUser extends org.springframework.security.core.userdetails.User {
/** The tenand id. */
private String tenantId;
Hope these steps help you to achieve what you want. There are many articles available which explains all these steps in detail. My implementation is deep embedded in my project hence it is not in a state which can be shared as working example.
Happy to answer any further questions