Reputation: 2408
I'm trying to create a multi-tenancy system for my CRM system. Basically every company using the software has their own sets of tables(aside from the tenants table itself). I would like to separate the data using a TenantID Column. The flow would be like that
Sign in
User adds new Meeting
There should also be a handful of endpoints and tables that don't use the tenantID at all
Here's what I have so far
import java.util.Map;
@Component
@RequiredArgsConstructor
//This class is supposed to set the tenantContextString in JPA
public class TenantIdentifierResolver implements CurrentTenantIdentifierResolver<String>, HibernatePropertiesCustomizer {
TenantContext tenantContext=null;
@Override
public String resolveCurrentTenantIdentifier() {
if(tenantContext.getCurrentTenant()==null)
throw new IllegalStateException("No tenant set");
return tenantContext.getCurrentTenant();
}
@Override
public void customize(Map<String, Object> hibernateProperties) {
hibernateProperties.put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, this);
}
@Override
public boolean validateExistingCurrentSessions() {
return false;
}
}
@Component
@RequestScope
//The controller can set the appropriate TenantContext for each request
public class TenantContext {
@Getter @Setter
private String currentTenant=null;
}
Here's my hibernate config
spring.jpa.properties.hibernate.multiTenancy = DISCRIMINATOR
spring.jpa.properties.hibernate.tenant_identifier_resolver = com.polaris.polaris.auth.tenant.TenantIdentifierResolver
But this gives me this error
Error creating bean with name 'scopedTarget.tenantContext': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton
I tried making the bean optional but it crashes as soon as I access it. also resolveCurrentTenantIdentifier is ran multiple times as soon as the application boots for some reason (which is probably the point at which the scope request tenantContext bean is unavailable). What is it used for and why can't I skip it? How can I realize the plan laid out above?
Upvotes: 0
Views: 65
Reputation: 181199
You have said two mostly-conflicting things:
JPA does not provide for any concrete entity class to be mapped to different tables in the same persistence unit. Thus, your main alternatives would be:
Use entity inheritance with the table-per-subclass strategy for substantially all your entities, giving each tenant its own collection of entity subclasses.
This does not scale well, and it probably incurs a performance penalty. Maybe it could work for you if you don't anticipate many tenants, but that's a mess I would not be eager to create for myself.
OR
Use a different persistence unit, with all its own tables, for each tenant.
The easiest way to do this would probably be to stand up a separate instance of the whole application for each tenant. They can share the same DB if you like. You can of course provide a common front end to handle sign in and redirection to the correct application instance. And inasmuch as you want to isolate tenants from each other, doing it with distinct application instances gives you even better isolation than just giving each tenant its own tables. And perhaps use a separate VM or container for each instance to reduce hardware requirements and improve isolation even more.
Upvotes: 0