Я начал преобразовывать существующее приложение Spring Boot (1.5.4.RELEASE) для поддержки мультитенантных возможностей.Поэтому я использую MySQL в качестве базы данных и Spring Data JPA в качестве механизма доступа к данным.Я использую мультитенантный подход на основе схемы.Как показано в документе Hibernate ниже
https://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch16.html
Я реализовал MultiTenantConnectionProvider
и CurrentTenantIdentifierResolver
интерфейсы, и я использую переменную ThreadLocal
для поддержки текущего арендатора для входящего запроса.
public class TenantContext {
final public static String DEFAULT_TENANT = "master";
private static ThreadLocal<Tenant> tenantConfig = new ThreadLocal<Tenant>() {
@Override
protected Tenant initialValue() {
Tenant tenant = new Tenant();
tenant.setSchemaName(DEFAULT_TENANT);
return tenant;
}
};
public static Tenant getTenant() {
return tenantConfig.get();
}
public static void setTenant(Tenant tenant) {
tenantConfig.set(tenant);
}
public static String getTenantSchema() {
return tenantConfig.get().getSchemaName();
}
public static void clear() {
tenantConfig.remove();
}
}
Затем я реализовал фильтр, и там я установил арендатора динамически, глядя на заголовок запроса, как показано ниже
String targetTenantName = request.getHeader(TENANT_HTTP_HEADER);
Tenant tenant = new Tenant();
tenant.setSchemaName(targetTenantName);
TenantContext.setTenant(tenant);
Это работает отлично, и теперь мойПриложение указывает на другую схему, основанную на значении заголовка запроса.
Однако существует основная схема, в которой я храню некоторые глобальные параметры, и мне нужно получить доступ к этой схеме, находясь в середине запроса для арендатора.Поэтому я попытался жестко закодировать переменную Threadlocal непосредственно перед тем вызовом базы данных в коде, как показано ниже.
Tenant tenant = new Tenant();
tenant.setSchemaName("master");
TenantContext.setTenant(tenant);
Однако это не указывает на основную схему, а вместо этого он пытается получить доступ к исходному набору схемы во времяфильтр.Что является причиной этого?Насколько я понимаю, Hibernate вызывает openSession () во время первого вызова базы данных для арендатора, и после того, как я пытаюсь вызвать другой вызов базы данных для «master», он все еще использует предыдущего арендатора, поскольку CurrentTenantIdentifierResolver вызывается только во время openSession ().Однако эти различные вызовы базы данных не вызывают внутри транзакции.Не могли бы вы помочь мне разобраться в проблеме с моим подходом и любыми предложениями по ее устранению
Спасибо, Кет
@ JonathanJohx, на самом деле я пытаюсь переопределить TenantContext, установленный фильтром, в одном изконтроллеры.Сначала я регистрируюсь в арендаторе, где TenantContext настроен именно на этого конкретного арендатора.Пока запрос находится в том арендаторе, я запрашиваю данные у мастера.Для этого я просто жестко прописал арендатора, как показано ниже
@RestController
@RequestMapping("/jobTemplates")
public class JobTemplateController {
@Autowired
JobTemplateService jobTemplateService;
@GetMapping
public JobTemplateList list(Pageable pageable){
Tenant tenant = new Tenant();
tenant.setSchemaName(multitenantMasterDb);
TenantContext.setTenant(tenant);
return jobTemplateService.list(pageable);
}