Код: Выделить всё
@Component
public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver, HibernatePropertiesCustomizer {
private static Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
public static final String DEFAULT_TENANT_ID = "notenant";
@Override
public String resolveCurrentTenantIdentifier() {
String tenant = TenantContext.getCurrentTenant();
if (tenant == null) {
return DEFAULT_TENANT_ID;
}
return tenant;
}
@Override
public void customize(Map hibernateProperties) {
hibernateProperties.put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, this);
}
@Override
public boolean validateExistingCurrentSessions() {
return true;
}
}
Для некоторых методов я хочу переключаться между арендаторами в одном запросе. Hibernate сохраняет tenantId, полученный из CurrentTenantIdentifierResolver, в сеансе, который он создает в начале запроса, но после создания сеанса невозможно изменить tenantId (или, по крайней мере, я еще не нашел чистого способа) . Мне удалось реализовать обходной путь, который просто отвязывает текущий сеанс и создает новый, однако это создает проблему, заключающуюся в том, что я не могу сделать методы, использующие этот «переключатель арендатора», транзакционными. Кроме того, это похоже на грязный обходной путь.
Вот код моего обходного пути («переключение арендатора»). TenantContext — это просто переменная ThreadLocal, в которой хранится идентификатор tenantId, указанный в заголовке запроса. CurrentTenantIdentifierResolver просто возвращает значение этой переменной, когда она вызывается из спящего режима.
Код: Выделить всё
@Override
public void changeTenant(String tenantId) {
unbindSession();
TenantContext.setCurrentTenant(tenantId); //ThreadLocal variable which holds the current tenant
bindSession();
}
@Override
public void bindSession() {
if (!TransactionSynchronizationManager.hasResource(entityManagerFactory)) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
TransactionSynchronizationManager.bindResource(entityManagerFactory, new EntityManagerHolder(entityManager));
}
}
@Override
public void unbindSession() {
if (TransactionSynchronizationManager.hasResource(entityManagerFactory)) {
EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.unbindResource(entityManagerFactory);
EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
}
}
В конечном итоге я бы хотел написать такой код:
Код: Выделить всё
@Transactional // Not possible with current solution
@Override
public void someServiceMethod() {
Information info = repository.getInfo() // Gets some data from tenant which made the request
changeTenant(someOtherTenantId) // Change the tenant without replacing the session
Information info2 = repository.getInfo() // Gets data for someOtherTenantId
// Perform other calculations etc.
}
Подробнее здесь: https://stackoverflow.com/questions/792 ... n-approach