有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JavaSpring与动态数据源

我有两个数据库结构,例如:

1-主_数据库:用户密码

2:客户数据库:客户A客户B客户C

我想访问主数据库,在验证数据后,重定向到客户数据库

我目前使用spring,并在applicationContext中配置它。xml

例如:

<bean id = "encryptionPassword" class = "utils.EncryptionPasswordSpring" />
<bean id = "dataSource" class = "com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method = "close">
<property name = "driverClass" value = "com.mysql.jdbc.Driver" />
<property name = "user" value = "user" />
<property name = "password" value = "123456" />
<property name = "jdbcUrl" value = "jdbc:mysql://localhost/testdb?useSSL = false" />
</bean>

有什么例子,建议吗?谢谢


共 (2) 个答案

  1. # 1 楼答案

    在应用程序中使用两组不同的配置配置两个bean。道具

    对于一种配置,您可以使用(beanName=dataSource1):

    @Configuration
    @EnableRetry
    public class DataSourceConfiguration {
    
        @Value("${datasource1.username}")
        private String username;
    
        @Value("${datasource1.password}")
        private String password;
    
        @Value("${datasource1.url}")
        private String connection;
    
        @Bean(name = "dataSource1")
        @Primary
        public DataSource mainDataSource() {
    
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
    
            dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
            dataSource.setUrl(connection);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            return dataSource;
        }
    }
    
  2. # 2 楼答案

    下面是我使用mybatis为动态数据源编写的代码。一个是主ds。另一个是读ds。希望它对你有用

    1. 使用AbstractRoutingDataSource定义DynamicDataSource
    import java.util.Map;
    
    import javax.sql.DataSource;
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class DynamicDataSource extends AbstractRoutingDataSource {
    
        @Override
        protected DataSource determineTargetDataSource() {
            return super.determineTargetDataSource();
        }
        
        /**
         */
        @Override
        protected Object determineCurrentLookupKey() {
            return DynamicDataSourceContextHolder.getDataSourceKey();
        }
        
        /**
         * @param defaultDataSource
         */
        public void setDefaultDataSource(Object defaultDataSource) {
            super.setDefaultTargetDataSource(defaultDataSource);
        }
        
        /**
         * @param dataSources
         */
        public void setDataSources(Map<Object, Object> dataSources) {
            super.setTargetDataSources(dataSources);
            DynamicDataSourceContextHolder.addDataSourceKeys(dataSources.keySet());
        }
    
    }
    
    
    
    1. 使用ThreadLocal在上下文中切换数据源
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.List;
    
    public class DynamicDataSourceContextHolder {
        
        private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>() {
            /**
             make main as default ds
             */
            @Override
            protected String initialValue() {
                return "main";
            }
        };
    
        /**
         * 
         */
        private static List<Object> dataSourceKeys = Collections.synchronizedList(new ArrayList<>());
    
        /**
         * switch ds
         * 
         * @param key
         */
        public static void setDataSourceKey(String key) {
            contextHolder.set(key);
        }
    
        /**
         * get ds
         * 
         * @return
         */
        public static String getDataSourceKey() {
            return contextHolder.get();
        }
    
        /**
         * reset ds
         */
        public static void clearDataSourceKey() {
            contextHolder.remove();
        }
    
        /**
         * judge if ds existed
         * 
         * @param key 
         * @return
         */
        public static boolean containDataSourceKey(String key) {
            return dataSourceKeys.contains(key);
        }
    
        /**
         * add ds
         * 
         * @param keys
         * @return
         */
        public static boolean addDataSourceKeys(Collection<? extends Object> keys) {
            return dataSourceKeys.addAll(keys);
        }
    
    }
    
    1. 通过应用程序注入不同的数据源。yml或应用程序。性质
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;
    
    import javax.sql.DataSource;
    
    import org.apache.ibatis.plugin.Interceptor;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.PlatformTransactionManager;
    
    
    @Configuration
    public class DataSourceConfig {
        
    
        @Primary
        @Bean
        @ConfigurationProperties("spring.datasource.main")
        public DataSource main() {
            return DataSourceBuilder.create().build();
        }
     
     
        @Bean
        @ConfigurationProperties("spring.datasource.read")
        public DataSource read() {
            return DataSourceBuilder.create().build();
        }
        
        @Bean
        public DataSource dynamicDataSource(
                @Qualifier("main") DataSource main,
                @Qualifier("read") DataSource read
                ) {
    
            Map<Object, Object> targetDataSources = new HashMap<>(2);
            targetDataSources.put("main", main);
            targetDataSources.put("read", read);
            DynamicDataSource dynamicDataSource = new DynamicDataSource();
            dynamicDataSource.setDefaultTargetDataSource(main); //default
            dynamicDataSource.setDataSources(targetDataSources);
            return dynamicDataSource;
        }
        
        @Bean
        public SqlSessionFactory sqlSessionFactory(
            @Qualifier("dynamicDataSource") DataSource dynamicDataSource)
                throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(dynamicDataSource);
            bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mappings/**/*.xml"));
            
            return bean.getObject();
        }
    
        @Bean(name = "sqlSessionTemplate")
        public SqlSessionTemplate sqlSessionTemplate(
            @Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory)
                throws Exception {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    
        @Bean
        public PlatformTransactionManager transactionManager(
            @Qualifier("dynamicDataSource") DataSource dynamicDataSource
        ) {
            return new DataSourceTransactionManager(dynamicDataSource);
        }
        
    }
    
    
    1. 定义一个AOP来控制哪个Dao方法使用哪个数据源。Dao是通过mybatis访问数据库的接口
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Order(-1)  
    @Component
    public class DynamicDataSourceAspect {
        private final static Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
    
        
    
        private final String[] QUERY_PREFIX = { 
            "select","get","find","query","quickGet"
        };
    
    
    
        @Pointcut("execution( * com.biz.dao..*.*(..))")
        public void daoAspect() {
        }
        
        @Before("daoAspect()")
        public void beforeDao(JoinPoint point) {
    
            boolean isQueryMethod = isQueryMethod(point.getSignature().getName());
            if (isQueryMethod) {
                switchDataSource("read");
            }
        }
    
        @After("daoAspect()")
        public void afterDao(JoinPoint point) {
            restoreDataSource();
        }
            
        //===============================private method
        private void switchDataSource(String key) {
            if (!DynamicDataSourceContextHolder.containDataSourceKey(key)) {
                logger.debug("======>DataSource [{}] doesn't exist, use default DataSource [{}] " + key);
            } else {
                // switch ds
                DynamicDataSourceContextHolder.setDataSourceKey(key);
                logger.debug("======>Switch DataSource to " + DynamicDataSourceContextHolder.getDataSourceKey());
             }      
        }
        
        private void restoreDataSource() {
            // reset to default ds
            DynamicDataSourceContextHolder.clearDataSourceKey();
        }
    
    
        private boolean isQueryMethod(String methodName) {
            for (String prefix : QUERY_PREFIX) {
                if (methodName.startsWith(prefix)) {
                    return true;
                }
            }
            return false;
        }
    }