Проблема DataSource Router в множественном доступе к множественным источникам данных - PullRequest
0 голосов
/ 20 сентября 2018

У меня есть проект весенней загрузки с использованием маршрутов источника данных в трех разных источниках данных.

Это моя конфигурация:

@Configuration
@EnableCaching
public class CachingConfiguration extends CachingConfigurerSupport {

    @Override
    public KeyGenerator keyGenerator() {
        return new EnvironmentAwareCacheKeyGenerator();
    }

}

-

public class DatabaseContextHolder {

    private static final ThreadLocal<DatabaseEnvironment> CONTEXT =
        new ThreadLocal<>();

    public static void set(DatabaseEnvironment databaseEnvironment) {
        CONTEXT.set(databaseEnvironment);
    }

    public static DatabaseEnvironment getEnvironment() {
        return CONTEXT.get();
    }

    public static void clear() {
        CONTEXT.remove();
    }

}

-

@Configuration
@EnableJpaRepositories(basePackageClasses = UsuarioRepository.class, 
                       entityManagerFactoryRef = "customerEntityManager", 
                       transactionManagerRef = "customerTransactionManager")
@EnableTransactionManagement
public class DatasourceConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "spring.ciclocairu.datasource")
    public DataSource ciclocairuDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.palmas.datasource")
    public DataSource palmasDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.megabike.datasource")
    public DataSource megabikeDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DataSource customerDataSource() {
        DataSourceRouter router = new DataSourceRouter();

        final HashMap<Object, Object> map = new HashMap<>(3);
        map.put(DatabaseEnvironment.CICLOCAIRU, ciclocairuDataSource());
        map.put(DatabaseEnvironment.PALMAS, palmasDataSource());
        map.put(DatabaseEnvironment.MEGABIKE, megabikeDataSource());
        router.setTargetDataSources(map);
        return router;
    }

    @Autowired(required = false)
    private PersistenceUnitManager persistenceUnitManager;

    @Bean
    @Primary
    @ConfigurationProperties("spring.jpa")
    public JpaProperties customerJpaProperties() {
        return new JpaProperties();
    }

    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean customerEntityManager(
        final JpaProperties customerJpaProperties) {

        EntityManagerFactoryBuilder builder =
            createEntityManagerFactoryBuilder(customerJpaProperties);

        return builder.dataSource(customerDataSource()).packages(Users.class)
            .persistenceUnit("customerEntityManager").build();
    }

    @Bean
    @Primary
    public JpaTransactionManager customerTransactionManager(
        @Qualifier("customerEntityManager") final EntityManagerFactory factory) {
        return new JpaTransactionManager(factory);
    }

    private JpaVendorAdapter createJpaVendorAdapter(
            JpaProperties jpaProperties) {
            AbstractJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
            adapter.setShowSql(jpaProperties.isShowSql());
            adapter.setDatabase(jpaProperties.getDatabase());
            adapter.setDatabasePlatform(jpaProperties.getDatabasePlatform());
            //adapter.setGenerateDdl(jpaProperties.isGenerateDdl());
            return adapter;
        }

    private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(
            JpaProperties customerJpaProperties) {
            JpaVendorAdapter jpaVendorAdapter =
                createJpaVendorAdapter(customerJpaProperties);
            return new EntityManagerFactoryBuilder(jpaVendorAdapter,
                customerJpaProperties.getProperties(), this.persistenceUnitManager);
        }







}

-

public class DataSourceRouter extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {

        if(DatabaseContextHolder.getEnvironment() == null)
            DatabaseContextHolder.set(DatabaseEnvironment.CICLOCAIRU);

        return DatabaseContextHolder.getEnvironment();
    }
}

-

public class EnvironmentAwareCacheKeyGenerator implements KeyGenerator {

    @Override
    public Object generate(Object target, Method method, Object... params) {

        String key = DatabaseContextHolder.getEnvironment().name() + "-" + (
            method == null ? "" : method.getName() + "-") + StringUtils
            .collectionToDelimitedString(Arrays.asList(params), "-");

        return key;
    }

}

Я устанавливаю источник данных, используя DatabaseContextHolder.set (DatabaseEnvironment.CICLOCAIRU);

Перейти к проблеме:

Например, два пользователя в разных источниках данных: 1 и 2

, если один пользователь использует источник данных 1, и отправить запрос, Другой пользователь, который использует источник данных 2, ваш следующийзапрос, вместо источника данных 2, это получить источник данных 1. Я думаю, что это ThreadLocal<DatabaseEnvironment> CONTEXT = new ThreadLocal<>(); было исключительно для запроса, но это не так.

Извините, если это не ясно.

На самом деле мне нужно, чтобы DataSurceRouter был эксклюзивным для каждого запроса, а запрос не был другим в другом.

Я ошибаюсь по поводуя думаю о DatasourceRouter или мой код плохой?

1 Ответ

0 голосов
/ 25 сентября 2018

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

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

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