Необходимо изменить базу данных. Имя URL источника данных динамически (многопользовательская база данных). - PullRequest
1 голос
/ 16 апреля 2019

Я использую Spring boot и Spring-data-Jpa. Я задаю URL источника данных, имя пользователя и пароль в файле application.properties. Он отлично работает для одного соединения с базой данных. Теперь я столкнулся с проблемой со структурой моего проекта базы данных, которая основана на том, что конкретный пользователь должен подключить свою базу данных и получить результат для конкретной базы данных пользователей, и я могу добиться этого с помощью абстрактного источника данных, DataSourceBuilder на уровне конфигурации (это один раз, когда я могу динамически изменять источник данных), но мне нужно менять источник данных каждый раз, когда контроллер нажимает.

Вот код для application.properties, и я ввел свой источник данных с помощью autowire.

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

spring.datasource.url=jdbc:sqlserver://test-datbase:1433;dbName1 spring.datasource.username=userName spring.datasource.password=Password spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver

Нужен код или метод, который я могу менять при подключении к базе данных при каждом обращении к контроллеру

Примечание: мне просто нужно изменить базу данных, мой диалект и все остальное будет таким же.

Ответы [ 5 ]

1 голос
/ 17 апреля 2019

Да, мы можем сделать это с помощью заполнителя.Установите -DdbName1=YOUR_DB_NAME в переменных окружения.Например:

spring.datasource.url=jdbc:sqlserver://test-datbase:1433;${dbName1}
spring.datasource.username=userName
spring.datasource.password=Password
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
0 голосов
/ 12 мая 2019

Я сделал проект, в котором я могу создать несколько источников данных с вашими конкретными наборами изменений, поэтому, если вам нужно добавить другой источник данных, это просто изменит ваш application.yml, больше не нужно менять код. Но если не использовать, просто удалите работающую жидкость!

При каждом обращении к контроллеру вам необходимо получить заголовок X-TenantId, который изменит ваш ThreadLocal, что, в свою очередь, изменит источник данных в соответствии с владельцем

Код завершен: https://github.com/dijalmasilva/spring-boot-multitenancy-datasource-liquibase

application.yml

spring:
  dataSources:
    - tenantId: db1
      url: jdbc:postgresql://localhost:5432/db1
      username: postgres
      password: 123456
      driver-class-name: org.postgresql.Driver
      liquibase:
        enabled: true
        default-schema: public
        change-log: classpath:db/master/changelog/db.changelog-master.yaml
    - tenantId: db2
      url: jdbc:postgresql://localhost:5432/db2
      username: postgres
      password: 123456
      driver-class-name: org.postgresql.Driver
    - tenantId: db3
      url: jdbc:postgresql://localhost:5432/db3
      username: postgres
      password: 123456
      driver-class-name: org.postgresql.Driver

TenantContext

public class TenantContext {

    private static ThreadLocal<String> currentTenant = new ThreadLocal<>();

    static String getCurrentTenant() {
        return currentTenant.get();
    }

    static void setCurrentTenant(String tenant) {
        currentTenant.set(tenant);
    }

    static void clear() {
        currentTenant.remove();
    }
}

Фильтр для контроллеров

public class TenantFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        final String X_TENANT_ID = "X-TenantID";

        final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        final String tenantId = httpServletRequest.getHeader(X_TENANT_ID);

        if (tenantId == null) {
            final HttpServletResponse response = (HttpServletResponse) servletResponse;
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.getWriter().write("{\"error\": \"No tenant header supplied\"}");
            response.getWriter().flush();
            TenantContext.clear();
            return;
        }

        TenantContext.setCurrentTenant(tenantId);
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

Класс конфигурации, если используется жидкостная база

@Configuration
@ConditionalOnProperty(prefix = "spring.liquibase", name = "enabled", matchIfMissing = true)
@EnableConfigurationProperties(LiquibaseProperties.class)
@AllArgsConstructor
public class LiquibaseConfiguration {

    private LiquibaseProperties properties;
    private DataSourceProperties dataSourceProperties;

    @Bean
    @DependsOn("tenantRoutingDataSource")
    public MultiTenantDataSourceSpringLiquibase liquibaseMultiTenancy(Map<Object, Object> dataSources,
                                                                      @Qualifier("taskExecutor") TaskExecutor taskExecutor) {
        // to run changeSets of the liquibase asynchronous
        MultiTenantDataSourceSpringLiquibase liquibase = new MultiTenantDataSourceSpringLiquibase(taskExecutor);
        dataSources.forEach((tenant, dataSource) -> liquibase.addDataSource((String) tenant, (DataSource) dataSource));
        dataSourceProperties.getDataSources().forEach(dbProperty -> {
            if (dbProperty.getLiquibase() != null) {
                liquibase.addLiquibaseProperties(dbProperty.getTenantId(), dbProperty.getLiquibase());
            }
        });

        liquibase.setContexts(properties.getContexts());
        liquibase.setChangeLog(properties.getChangeLog());
        liquibase.setDefaultSchema(properties.getDefaultSchema());
        liquibase.setDropFirst(properties.isDropFirst());
        liquibase.setShouldRun(properties.isEnabled());
        return liquibase;
    }

}

Код завершен: https://github.com/dijalmasilva/spring-boot-multitenancy-datasource-liquibase

0 голосов
/ 26 апреля 2019

с помощью ссылки ниже, я могу установить несколько источников данных при запуске сервера

https://fizzylogic.nl/2016/01/24/make-your-spring-boot-application-multi-tenant-aware-in-2-steps/

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

public class MultitenantConfiguration {
  @Bean
@ConfigurationProperties(
        prefix = "spring.datasource"
)
public DataSource dataSource(ArrayList<String> names) {


    Map<Object,Object> resolvedDataSources = new HashMap<>();

    for(String  dbName: names) {

        DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(this.getClass().getClassLoader());
        dataSourceBuilder.driverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver")
                .url("jdbc:sqlserver://abc.server;databaseName="+dbName+"")
                .username("userName")
                .password("Password");


        resolvedDataSources.put(dbName, dataSourceBuilder.build());
    }



    MultitenantDataSource dataSource = new MultitenantDataSource();
    dataSource.setDefaultTargetDataSource(defaultDataSource());
    dataSource.setTargetDataSources(resolvedDataSources);
    dataSource.afterPropertiesSet();


    return dataSource;
}

/**
 * Creates the default data source for the application
 * @return
 */
private DataSource defaultDataSource() {
    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(this.getClass().getClassLoader())
            .driverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver")
            .url("jdbc:abc.server;databaseName=test")
            .username("UserName")
            .password("Password");

    return dataSourceBuilder.build();
}
  }
0 голосов
/ 17 апреля 2019

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

Мое решение: введите описание ссылки здесь

и укажите свой собственный класс PersistenceConfiguration при выборе базы данных введите описание ссылки здесь

если вы хотите динамически выбирать базу, используя методы в коде Java

0 голосов
/ 16 апреля 2019

Вот как я могу решить эту проблему: вы можете создать 2 отдельных источника данных.Создайте квалификаторы для них и добавьте их в свой контроллер.Затем в конечной точке напишите логику, которая выберет один из источников для сохранения информации.

Вот как добавить дополнительный источник данных в ваш проект:

https://medium.com/@joeclever/using-multiple-datasources-with-spring-boot-and-spring-data-6430b00c02e7

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...