代码之家  ›  专栏  ›  技术社区  ›  Jeterson Miranda Gomes

多数据源访问中的数据源路由器问题

  •  0
  • Jeterson Miranda Gomes  · 技术社区  · 7 年前

    我在三个不同的数据源中使用了数据源路由。

    这是我的配置:

    @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;
        }
    
    }
    

    例如,不同数据源中的两个用户:1和2

    如果一个用户使用数据源1,并发送请求, 另一个用户使用数据源2, 您的下一个请求不是数据源2,而是获取数据源1。我想这个 ThreadLocal<DatabaseEnvironment> CONTEXT = new ThreadLocal<>(); 是唯一的请求,但这似乎不是这样。

    实际上,我需要datasourcerouter对每个请求都是独占的,并且一个请求不能在另一个请求中插入。

    我认为DatasourceRouter错了还是我的代码不好?

    1 回复  |  直到 7 年前
        1
  •  1
  •   gtatr    7 年前

    当服务器回收一个线程时,thread局部变量已经从上一个循环中设置了该值,因此您需要在每次请求后刷新该值,使线程处于干净状态。