MultiTenant Hibernate + Spring boot - как предотвратить поиск соединения во время запуска сервера - PullRequest
0 голосов
/ 25 февраля 2020

Мы используем мультитенантную спящий режим Hibernate + Spring, как описано в Мультитенантность в Hibernate . Мы предоставляем MultiTenantConnectionProvider и CurrentTenantIdentifierResolver при создании менеджера сущностей (см. Пример ниже).

В нашем MultiTenantConnectionProvider целевая база данных для арендатора не настроена статически. Вместо этого он динамически определяет данные целевой базы данных текущего арендатора, вызывая другую службу, а затем создает для нее источник данных.

Теперь мы сталкиваемся с проблемой, заключающейся в том, что при запуске весеннего загрузочного сервера Hibernate вызывает метод MultiTenantConenctionProvider.getAnyConnection (). Во время запуска сервера в этом контексте нет арендатора, и, следовательно, у нас нет базы данных для создания подключения. Кроме того, у нас нет фиктивной базы данных в нашей настройке, которую мы можем использовать во время запуска сервера

  1. Если мы вернем null, при запуске сервера произойдет сбой с NullPointerException
  2. Если мы переопределим При вызове метода anyConnection () и генерации исключения (как можно видеть из кода ниже) сервер просто регистрирует исключение и продолжает запуск сервера.

При значении 2 все работает нормально, и мы способен добиться прогресса. Однако мы действительно хотим избавиться от этого ненужного исключения, которое регистрируется при каждом перезапуске сервера весенней загрузки.

Мы ищем способ отключить режим гибернации при попытке подключения к БД во время запуска сервера, особенно когда мультитенантная стратегия hibernate установлена. Это поведение несовместимо с мультитенантным программным обеспечением

Есть ли какой-либо способ, которым мы можем запретить hiberate пытаться получить соединение (т.е. сделать вызов MultiTenantConenctionProvider.getAnyConnection ()) во время запуска сервера?

Пожалуйста, сообщите

Ниже приведен пример конфигурации Spring

@Configuration
@EnableTransactionManagement
public class MultiTenantHibernateJpaConfig {

    @Autowired
    private JpaProperties jpaProperties;

    @Bean
    public MultiTenantConnectionProvider multiTenantConnectionProvider() {
        return new MultiTenantConnectionProviderImpl();
    }

    @Bean
    public CurrentTenantIdentifierResolver currentTenantIdentifierResolver() {
        return new CurrentTenantIdentifierResolverImpl();
    }

    @Value("${jpaconfig.packages-to-scan:#{null}}")
    private String packagesToScan;

    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(MultiTenantConnectionProvider multiTenantConnectionProvider,
                                                                       CurrentTenantIdentifierResolver currentTenantIdentifierResolver) {

        Map<String, Object> hibernateProps = new LinkedHashMap<>();
        hibernateProps.put(Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
        hibernateProps.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
        hibernateProps.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver);

        hibernateProps.put("javax.persistence.schema-generation.database.action", "none");
        hibernateProps.put("javax.persistence.query.timeout", "5");
        hibernateProps.put(Environment.DIALECT, "org.hibernate.dialect.Oracle10gDialect");
        hibernateProps.putAll(this.jpaProperties.getProperties());

        LocalContainerEntityManagerFactoryBean result = new LocalContainerEntityManagerFactoryBean();
        if(packagesToScan != null) {
            //handle multiple packages separated by comma
            result.setPackagesToScan(packagesToScan.split("\\s*,\\s*"));
        }
        result.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        result.setJpaPropertyMap(hibernateProps);

        return result;
    }

Ниже приведена реализация MultiTenantConnectionProvider

public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {

    private static final long serialVersionUID = 1L;


    public MultiTenantConnectionProviderImpl()
    {
    }

    @Override
    protected DataSource selectAnyDataSource()
    {
        return null;
    }

    @Override
    protected DataSource selectDataSource(String tenantIdentifier) {
        //This in turn makes a call to a remote service to fetch current tenant 
        //database details and then creates a datasource for it.
        return DataSourceManager.getDataSource(tenantIdentifier);
    }

    @Override
    public Connection getAnyConnection() throws SQLException{
        //Called during server startup. Cannot do any thing  as tenant is not known
        // and there is no default datasource
        throw new SQLException("not implemented in multi-tenant environment");
    }

    @Override
    public void releaseAnyConnection(Connection connection) throws SQLException
    {
        //Called during server startup. Cannot do any thing  as tenant is not known
        // and there is no default datasource
        throw new SQLException("not implemented in multi-tenant environment");
    }
}

1 Ответ

0 голосов
/ 25 февраля 2020

Это вызывается только во время запуска, почему бы не использовать tenantIdentifier по умолчанию только для запуска?

Обновление:

Так что, если это невозможно. Почему бы вам не реализовать интерфейс Connection с классом DummyConnection и вернуть его при запуске?

...