精华内容
下载资源
问答
  • SpringBoot 多数据源切换

    千次阅读 2019-06-29 20:40:01
    SpringBoot多数据源切换 目的: 1)读写库在代码端实现 2)需要操作数据库的时候需要使用 核心类 核心类AbstractRoutingDataSource,这个类是一个抽象化的DataSource类。可以用来选择个数据源,确认数据源。 ...

    SpringBoot多数据源切换

    目的:
    1)读写库在代码端实现
    2)需要操作多数据库的时候需要使用

    核心类

    核心类AbstractRoutingDataSource,这个类是一个抽象化的DataSource类。可以用来选择多个数据源,确认数据源。
    核心方法:

    • determineCurrentLookupKey() 通过重写这个方法来决定那个数据源
    • setTargetDataSources(Map<Object, Object> targetDataSources)通过set多个数据源来切换

    运行流程:通过这个determineCurrentLookupKey这个方法来确认我们的数据源,比对设置的DataSource的Map对象来获取相关链接。

    逻辑调用图

    1.初始化
    在这里插入图片描述
    2.访问过程
    在这里插入图片描述

    主要逻辑代码

    配置多数据源

    Configuration
    @MapperScan(basePackages = "com.example.multdatasources.dao")
    public class DynamicDataSourceConfiguration {
    
        @Bean
        @ConfigurationProperties(prefix = "multiple.datasource.master")
        //需要在配置文件中获取相关东西
        public DataSource dbMaster() {
            return DruidDataSourceBuilder.create().build();
        }
    
        @Bean
        @ConfigurationProperties(prefix = "multiple.datasource.slave")
        //需要在配置文件中获取相关东西
        public DataSource dbSlave() {
            return DruidDataSourceBuilder.create().build();
        }
    
        @Bean
        public DataSource dynamicDataSource() {
            DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
            dataSource.setDefaultTargetDataSource(dbMaster());
            Map<Object, Object> dataSourceMap = new HashMap<>(2);
            dataSourceMap.put(DataSourceKey.DB_MASTER, dbMaster());
            dataSourceMap.put(DataSourceKey.DB_salve, dbSlave());
            //设置所有数据源
            dataSource.setTargetDataSources(dataSourceMap);
            return dataSource;
        }
    
    
        @Bean
        public SqlSessionFactory sqlSessionFactory() throws Exception {
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setDataSource(dynamicDataSource());
            //此处设置为了解决找不到mapper文件的问题
            sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
            return sqlSessionFactoryBean.getObject();
        }
    
        @Bean
        public SqlSessionTemplate sqlSessionTemplate() throws Exception {
            return new SqlSessionTemplate(sqlSessionFactory());
        }
    
    

    继承实现AbstractRoutingDataSource:

    public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
        //获取相关的数据源信息
        @Override
        public Object determineCurrentLookupKey() {
            return DynamicDataSourceContextHolder.get();
        }
    }
    

    切面处理:

    @Aspect
    @Component
    //@Order(-1)
    public class MultSourceAop {
        @Before("@annotation(targetSource)")
        public void doBefore(JoinPoint joinPoint, TargetSource targetSource){
            DataSourceKey key=targetSource.dataSourceKey();
            if(key==DataSourceKey.DB_MASTER){
                DynamicDataSourceContextHolder.set(key);
            }else{
                DynamicDataSourceContextHolder.set(DataSourceKey.DB_salve);
            }
        }
    
        @After("@annotation(targetSource)")
        public void doAfter(JoinPoint  joinPoint, TargetSource targetSource){
            DynamicDataSourceContextHolder.remove();
        }
    }
    

    多数据源Holder:

    public class DynamicDataSourceContextHolder {
    
        private static final ThreadLocal<DataSourceKey> currentDatesource = new ThreadLocal<>();
    
        //获取当前链接文件
        public static Object get(){
            return currentDatesource.get();
        }
    
        //消除当前链接
        public static void remove(){
            currentDatesource.remove();
        }
    
        //设置当前链接
        public static void set(DataSourceKey value) {
            currentDatesource.set(value);
        }
    }
    

    错误汇总

    1.java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$PooledDataSourceConfiguration
    解答:这是因为配置了自动加载数据源,我们也没有配置相关的默认数据源
    方案:

    • 禁止启动默认数据源配置信息(推荐)

    2.bound statement(not found)
    解答:是因为mapper文件和Mapper.java的文件不能映射起来,所以需要查看一下XML文件的配置

    待确认问题

    1.为啥配置中的配置信息是这样的形式,目的搞定出DataSource类的配置怎么加载的
    drive-class-name和
    2.为啥有些回去默认的数据源
    答案:因为在选择数据库的时候,如果和数据源的mapper对应不上配置的话,就在determine的时候选择default的数据源;即spring.datasource.url配置的数据源

    需要改善的东西

    明天希望完成的东西:
    1.事务管理测试还没做
    2.最好是能做一些关于自动启动的类

    测试代码地址分享:https://gitee.com/eason93/MultDataSources

    世界很复杂,今天多搞点以后轻松点;哈哈

    展开全文
  • Springboot多数据源切换

    千次阅读 2019-04-14 14:44:07
    springboot 数据源的配置 解决问题, 一个springboot 项目操作个数据库的数据 新建springboot项目 添加pom依赖 <dependency> <groupId>org.mybatis.spring.boot</groupId> ...

    Springboot-DynamicData

    springboot 多个数据源的配置
    解决问题, 一个springboot 项目操作多个数据库的数据

    新建springboot项目 添加pom依赖

          <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
            </dependency>
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper-spring-boot-starter</artifactId>
                <version>1.2.5</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.40</version>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.4</version>
            </dependency>
    

    新建 config 包添加配置项

    • 新建枚举类多个数据源
    public enum DatabaseTypeEnum {
        PRIMARY("1"), USER("2");
    
        private String code;
    
        DatabaseTypeEnum(String code) {
            this.code = code;
        }
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public static DatabaseTypeEnum getDatabaseTypeEnum(String code) {
            for (DatabaseTypeEnum databaseTypeEnum : DatabaseTypeEnum.values()) {
                if (databaseTypeEnum.getCode().equals(code)) {
                    return databaseTypeEnum;
                }
            }
            return null;
        }
    }
    
    • 新建 HikariConfig 类,添加数据源配置
    import com.zaxxer.hikari.HikariDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    
    /**
     * @author yyb
     * @time 2019/3/27
     */
    @Service
    public class HikariConfig {
        @Value("${spring.datasource.username}")
        private String userName;
        @Value("${spring.datasource.password}")
        private String password;
        @Value("${spring.datasource.driver-class-name}")
        private String driverClassName;
        @Value("${spring.datasource.min-idle}")
        private Integer minIdle;
        @Value("${spring.datasource.max-active}")
        private Integer maxActive;
        @Value("${spring.datasource.validation-query}")
        private String validationQuery;
        @Value("${spring.datasource.connection-timeout}")
        private Integer connectionTimeout;
        @Value("${spring.datasource.max-left-time}")
        private Integer maxLeftTime;
        @Value("${spring.datasource.validation-time-out}")
        private Integer validationTimeout;
        @Value("${spring.datasource.idle-time-out}")
        private Integer idleTimeout;
        @Value("${spring.datasource.connection-init-sql}")
        private String connectionInitSql;
    
        /**
         * 配置Hikari数据连接池
         *
         * @param url 数据源
         * @return 连接池对象
         */
        public HikariDataSource getHikariDataSource(String url) {
            com.zaxxer.hikari.HikariConfig config = new com.zaxxer.hikari.HikariConfig();
            config.setMinimumIdle(minIdle);
            config.setMaximumPoolSize(maxActive);
            config.setConnectionTestQuery(validationQuery);
            config.setJdbcUrl(url);
            config.setUsername(userName);
            config.setPassword(password);
            config.setDriverClassName(driverClassName);
            config.setConnectionTimeout(connectionTimeout);
            config.setMaxLifetime(maxLeftTime);
            config.setValidationTimeout(validationTimeout);
            config.setConnectionInitSql(connectionInitSql);
            return new HikariDataSource(config);
        }
    
        /**
         * 用于两个库账号密码不一样的时候
         *
         * @param url
         * @param userName
         * @param passwod
         * @return
         */
        public HikariDataSource getHikariDataSource(String url, String userName, String passwod) {
            com.zaxxer.hikari.HikariConfig config = new com.zaxxer.hikari.HikariConfig();
            config.setMinimumIdle(minIdle);
            config.setMaximumPoolSize(maxActive);
            config.setConnectionTestQuery(validationQuery);
            config.setJdbcUrl(url);
            config.setUsername(userName);
            config.setPassword(passwod);
            config.setConnectionTimeout(connectionTimeout);
            config.setDriverClassName(driverClassName);
            config.setMaxLifetime(maxLeftTime);
            config.setValidationTimeout(validationTimeout);
            config.setConnectionInitSql(connectionInitSql);
            return new HikariDataSource(config);
        }
    
    • 新建DynamicDataSourceConfig 类配置两个数据源
    import cn.abel.enums.DatabaseTypeEnum;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    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 javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author yyb
     * @time 2019/3/27
     */
    @Configuration
    @MapperScan(basePackages = "cn.abel.dao")
    public class DynamicDataSourceConfig {
        @Value("${spring.datasource.primary.url}")
        private String primaryUrl;
        @Value("${spring.datasource.user.url}")
        private String userUrl;
        @Value("${mybatis.mapper-locations}")
        private String resources;
        //当两个数据库连接账号密码不一样时
    //    @Value("${spring.datasource.user.username}")
    //    private String userName;
    //    @Value("${spring.datasource.user.password}")
    //    private String password;
    
        @Autowired
        private HikariConfig hikariConfig;
    
        @Primary
        @Bean(name = "primaryDataSource")
        public DataSource getPrimaryDataSource() {
            return hikariConfig.getHikariDataSource(primaryUrl);
        }
    
        @Bean(name = "userDataSource")
        public DataSource getUserDataSource() {
            return hikariConfig.getHikariDataSource(userUrl);
        }
    
    
        //当两个数据库连接账号密码不一样时使用
    //    @Bean(name = "userDataSource")
    //    public DataSource getUserDataSource() {
    //        return hikariConfig.getHikariDataSource(userUrl, userName, password);
    //    }
    
    
        @Bean("dynamicDataSource")
        public DynamicDataSource dynamicDataSource(@Qualifier("primaryDataSource") DataSource primaryDataSource,
                                                   @Qualifier("userDataSource") DataSource miaoMoreDataSource) {
            Map<Object, Object> targetDataSources = new HashMap<>();
            targetDataSources.put(DatabaseTypeEnum.PRIMARY, primaryDataSource);
            targetDataSources.put(DatabaseTypeEnum.USER, miaoMoreDataSource);
    
            DynamicDataSource dataSource = new DynamicDataSource();
            dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法
            dataSource.setDefaultTargetDataSource(primaryDataSource);// 默认的datasource设置为myTestDbDataSource
            return dataSource;
        }
    
        /**
         * 根据数据源创建SqlSessionFactory
         */
        @Bean
        public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(dynamicDataSource);
            bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(resources));
            return bean.getObject();
        }
    }
    
    • 新建 DynamicDataSourceContextHolder 数据源切换路由
    import cn.abel.enums.DatabaseTypeEnum;
    
    /**
     * @author yyb
     * @time 2019/3/27
     */
    public class DynamicDataSourceContextHolder {
        private static final ThreadLocal<DatabaseTypeEnum> contextHolder = new ThreadLocal<>();
    
        public static void setDatabaseType(DatabaseTypeEnum type){
            contextHolder.set(type);
        }
    
        public static DatabaseTypeEnum getDatabaseType(){
            return contextHolder.get();
        }
    
        public static void resetDatabaseType() {
            contextHolder.set(DatabaseTypeEnum.PRIMARY);
        }
    }
    
    
    • 新建 DynamicDataSource 动态数据源
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    /**
     * @author yyb
     * @time 2019/3/27
     */
    public class DynamicDataSource extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            return DynamicDataSourceContextHolder.getDatabaseType();
        }
    }
    
    

    使用

    在service 层调用dao 层的时候,进行数据源切换操作

    
        public List<News> getByMap(Map<String, Object> map) {
            //重置数据源,切换为默认数据源
            DynamicDataSourceContextHolder.resetDatabaseType();
            return newsDao.getByMap(map);
        }
    
    

    在需要的地方切换第二个数据源

    
      	public User getById(Integer id){
    		 //切换为配置第二数据源
    		 
    DynamicDataSourceContextHolder.setDatabaseType(DatabaseTypeEnum.USER);
    		return userDao.getById(id);
    	}
    

    完整代码:https://github.com/527515025/springBoot/tree/master/springboot-dynamicDataSource

    展开全文
  • springboot多数据源切换

    2020-09-23 11:08:54
    实际工作中,我们会遇到springboot项目初始化启动时候,不能指定具体连接哪个数据源的时候,不同的接口连接不同的数据源或者前端页面指定连接某个数据源等等情况,就会遇到动态数据源切换的问题。 一.通用的动态...

           实际工作中,我们会遇到springboot项目初始化启动时候,不能指定具体连接哪个数据源的时候,不同的接口连接不同的数据源或者前端页面指定连接某个数据源等等情况,就会遇到动态数据源切换的问题。

    一.通用的动态数据源切换场景

    Spring boot提供了AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源,这样我们可以在执行查询之前,设置使用的数据源。实现可动态路由的数据源,在每次数据库查询操作前执行。它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源.

    1.继承AbstractRoutingDataSource,重写determineCurrentLookupKey方法

    public class DynamicDataSource extends AbstractRoutingDataSource {

       private static final ThreadLocal<String> dataSourceKey = ThreadLocal.withInitial(() -> "defaultDataSource");

       private static Map<Object,Object> dataSourceMap = new ConcurrentHashMap<>(10);

       static {

            dataSourceMap .put("defaultDataSource", SpringUtils.getBean("defaultDataSource"));

       }

        @Override

        protected Object determineCurrentLookupKey() {

            return DynamicDataSource.dataSourceKey.get();

        }

        public static void serDataSource(String dataSource){

            DynamicDataSource.dataSourceKey.set(dataSource);

            DynamicDataSource dynamicDataSource = (DynamicDataSource)SpringUtils.getBean("dataSource")

             dynamicDataSource.afterPropertiesSet();

        }

        public static String getDataSource(){

           return DynamicDataSource.dataSourceKey.get();

         }

        public static void clear(){

           DynamicDataSource.dataSourceKey.remove();

     

        }

    2.把AbstractRoutingDataSource注入到容器中

    @Configuration

    public class DataSourceConfig{

         @Bean

         @ConfigurationProperties("spring.datasource.druid")

        public DataSource defaultDataSource(){

             return DruidDataSourceBuilder.create().builder();

         }

         @Bean
         @Primary

         @DependsOn({"springUtils","defaultDataSource"})
        public DynamicDataSource dataSource() {
           DynamicDataSource dynamicDataSource  = new DynamicDataSource ();

           dynamicDataSource.setTargetDataSource(DynamicDataSource .dataSourceMap );

           return dynamicDataSource ;
        }

    }

    3.实现SpringUtils工具类并注入到spring容器中

    @Component
    public class SpringUtils implements ApplicationContextAware {
     
        private static ApplicationContext applicationContext;
     
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
     
        public static <T> T getBean(Class<T> tClass){
            return applicationContext.getBean(tClass);
        }
     
        public static Object getBean(String name) {
            return applicationContext.getBean(name);
        }
     
        public static HttpServletRequest getCurrentReq() {
            ServletRequestAttributes requestAttrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (requestAttrs == null) {
                return null;
            }
            return requestAttrs.getRequest();
        }
     
        public static String getMessage(String code, Object... args) {
            LocaleResolver localeResolver = getBean(LocaleResolver.class);
            Locale locale = localeResolver.resolveLocale(getCurrentReq());
            return applicationContext.getMessage(code, args, locale);
        }

       public satic String getProperty(String key){

           return SpringUtils.applicationContext.getEnvironment.getProperty(key);

       }
     
    }

    4.自定义注解和切面,实现方法级别是否切换数据源

    @Document

    @Retention(retentionPolicy.RUNTIME)

    @Target(ElementType.METHOD)

    public @interface OperDataSource {

    }

     

    @Component
    @Aspect
    public class DataSourceAspect {

        @Autowired

        private DataSourceProperties basicProperties;


        @Pointcut("@annotation(com.xxxxxx.OperDataSource )")
        public void dataSourcePointCut(){

        }

        @Before(value="dataSourcePointCut()")
        public void beforeMerhod(JoinPoint jp){
           DruidDataSource druidDataSource = new DruidDataSource();

           druidDataSource.setUrl(basicProperties.getUrl());

           druidDataSource.setUsername(basicProperties.getUsername());

           druidDataSource.setPassword(basicProperties.getPassword());

           DynamicDataSource.dataSourceMap.put("dbKey",druidDataSource);
            DataSourceContextHolder.setDataSource("dbKey");
        }

        @After("dataSourcePointCut()")
        public void afterMethod(JoinPoint jp){
            DynamicDataSource.clear();
        }
    }

    二. 页面切换数据源场景

    1.排除掉Druid自动注入

    @SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class})

    2.手动实现DruidDataSource的bean

    @Configuration

    public class DataSourceConfig{

     private DataSourceProperties basicProperties;

      public DataSource dataSource() throws IOException, SQLException{

          DruidDataSource druidDataSource = DruidDataSourceBuilder.create().buid();

          druidDataSource.restart();

          druidDataSource.setPassword(Base64.Encoder getEncoder(basicProperties.getPassword()));

      }  

    }

    3.自定义接口,实现重新设置数据源

    DruidDataSource druidDataSource = (DruidDataSource)SpringUtils.getBean("dataSource");

    druidDataSource.restart();

    druidDataSource.setDriverClassName(driverClassName);

    druidDataSource.setUrl(url);

    ......

     如果需要改写yml文件内容

    需要引入

    <dependency>
        <groupId>org.yaml</groupId>
        <artifactId>snakeyaml</artifactId>
        <version>1.26</version>
    </dependency>

    展开全文
  • springboot多数据源切换mysql+sql server,该事例代码demo,下载下来就能使用,使用工具idea,自行安装mysql和sql server
  • SpringBoot多数据源切换,AOP实现动态数据源切换 操作数据一般都是在DAO层进行处理,可以选择直接使用JDBC进行编程 或者是使用个DataSource 然后创建个SessionFactory,在使用Dao层的时候通过不同的...

    SpringBoot多数据源切换,AOP实现动态数据源切换

    操作数据一般都是在DAO层进行处理,可以选择直接使用JDBC进行编程
    或者是使用多个DataSource 然后创建多个SessionFactory,在使用Dao层的时候通过不同的SessionFactory进行处理,不过这样的入侵性比较明显,一般的情况下我们都是使用继承HibernateSupportDao进行封装了的处理,如果多个SessionFactory这样处理就是比较的麻烦了,修改的地方估计也是蛮多的
    最后一个,也就是使用AbstractRoutingDataSource的实现类通过AOP或者手动处理实现动态的使用我们的数据源,这样的入侵性较低,非常好的满足使用的需求。比如我们希望对于读写分离或者其他的数据同步的业务场景

    ●单数据源的场景(一般的Web项目工程这样配置进行处理,就已经比较能够满足我们的业务需求)
    多数据源多SessionFactory这样的场景,估计作为刚刚开始想象想处理在使用框架的情况下处理业务,配置多个SessionFactory,然后在Dao层中对于特定的请求,通过特定的SessionFactory即可处理实现这样的业务需求,不过这样的处理带来了很多的不便之处,所有很多情况下我们宁愿直接使用封装的JDBC编程,或者使用Mybatis处理这样的业务场景

    ●使用AbstractRoutingDataSource 的实现类,进行灵活的切换,可以通过AOP或者手动编程设置当前的DataSource,不用修改我们编写的对于继承HibernateSupportDao的实现类的修改,这样的编写方式比较好,至于其中的实现原理,让我细细到来。我们想看看如何去应用,实现原理慢慢的说!

    ●编写AbstractRoutingDataSource的实现类,HandlerDataSource就是提供给我们动态选择数据源的数据的信息,我们这里编写一个根据当前线程来选择数据源,然后通过AOP拦截特定的注解,设置当前的数据源信息,也可以手动的设置当前的数据源,在编程的类中。

    /**
     * 动态数据源
     *
     * @author
     * @date 2017年3月5日 上午9:11:49
     */
    public class DynamicDataSource extends AbstractRoutingDataSource {
    	private Map<Object, Object> allResolvedDataSources = new HashMap<>();
    
    	@Override
    	protected Object determineCurrentLookupKey() {
    		return DataSourceContextUtil.getDataSourceType();
    	}
    
    	/**
    	 * 添加数据源
    	 * @param name
    	 * @param dataSource
    	 */
    	public void addDataSource(Object name,DataSource dataSource){
    		if(allResolvedDataSources.containsKey(name))
    			allResolvedDataSources.remove(name);
    		allResolvedDataSources.put(name,dataSource);
    		setTargetDataSources(allResolvedDataSources);
    	}
            /**
             * 删除数据源
             * @param name
             * @return
             */
    	    public Object deleteDataSource(Object name){
    		Object rst = null;
    		if(allResolvedDataSources.containsKey(name))
    		{
    			rst = allResolvedDataSources.get(name);
    			allResolvedDataSources.remove(name);
    			setTargetDataSources(allResolvedDataSources);
    		}
    		return rst;
    	    }
    
            /**
             * 检查数据源是否存在
             * @param name
             * @return
             */
    	    public Boolean isExistDataSource(Object name){
    	        return allResolvedDataSources.containsKey(name);
                }
    }
    

    ●设置动态选择的Datasource,这里的Set方法可以留给AOP调用,或者留给我们的具体的Dao层或者Service层中手动调用,在执行SQL语句之前。

    /**
     * 动态数据源
     *
     * @author
     * @date 2017年3月5日 上午9:11:49
     */
    public class DynamicDataSource extends AbstractRoutingDataSource {
    	private Map<Object, Object> allResolvedDataSources = new HashMap<>();
    
    	@Override
    	protected Object determineCurrentLookupKey() {
    		return DataSourceContextUtil.getDataSourceType();
    	}
    
    	/**
    	 * 添加数据源
    	 * @param name
    	 * @param dataSource
    	 */
    	public void addDataSource(Object name,DataSource dataSource){
    		if(allResolvedDataSources.containsKey(name))
    			allResolvedDataSources.remove(name);
    		allResolvedDataSources.put(name,dataSource);
    		setTargetDataSources(allResolvedDataSources);
    	}
            /**
             * 删除数据源
             * @param name
             * @return
             */
    	public Object deleteDataSource(Object name){
    		Object rst = null;
    		if(allResolvedDataSources.containsKey(name))
    		{
    			rst = allResolvedDataSources.get(name);
    			allResolvedDataSources.remove(name);
    			setTargetDataSources(allResolvedDataSources);
    		}
    		return rst;
    	}
    
            /**
             * 检查数据源是否存在
             * @param name
             * @return
             */
    	public Boolean isExistDataSource(Object name){
    	    return allResolvedDataSources.containsKey(name);
            }
    }
    
    

    ●在项目启动的时候初始化所有的数据源信息,通过DynamicDataSource类以键值对的形式存储

            DruidDataSource dataSource = dataSource();
            DruidDataSource masterDataSource = masterDataSource();
            DruidDataSource clusterDataSource = clusterDataSource();
            //DruidDataSource bizDataSource = bizDataSource();
    
            try {
                dataSource.init();
                clusterDataSource.init();
                masterDataSource.init();
    
             //   bizDataSource.init();
            }catch (SQLException sql){
                sql.printStackTrace();
            }
    
            DynamicDataSource dynamicDataSource = new DynamicDataSource();
            dynamicDataSource.addDataSource(DSEnum.DATA_SOURCE_NAME,dataSource);                     dynamicDataSource.addDataSource(DSEnum.MASTER_DATA_SOURCE_NAME,masterDataSource);
         dynamicDataSource.addDataSource(DSEnum.CLUSTER_DATA_SOURCE_NAME,clusterDataSource);
     DataSourceContextUtil.setDataSourceType(DSEnum.DATA_SOURCE_NAME);//设置默认的数据源的Key
     dynamicDataSource.setDefaultTargetDataSource(dataSource);//设置默认的数据源

    ●代码使用方法,注意的是这里使用过后需要调用清空的方法,让其返回默认的数据源,否则将会带着这个数据源满世界的报错找不到表,找不到列,映射不到类。。。。。。

    DataSourceContextUtil.setDataSourceType(DSEnum.CLUSTER_DATA_SOURCE_NAME);
            String sql2="select * from sys_config";
         List<Map<String,Object>>sqlListPage2=commonDao.getSqlListNotPage(sql2.toString(),null);
            DataSourceContextUtil.clearDataSourceType();

    下面是我使用的枚举类型,用来当做Key来使用的

    /**
     * 
     * 多数据源的枚举
     *
     * @author
     * @date 2017年3月5日 上午10:15:02
     */
    public interface DSEnum {
    
    	String DATA_SOURCE_NAME = "dataSource";		//base数据源
    
    	String MASTER_DATA_SOURCE_NAME = "masterDataSource";		//base数据源
    
    	String CLUSTER_DATA_SOURCE_NAME = "clusterDataSource";		//base数据源
    }

     

    展开全文
  • SpringBoot多数据源实现以实现AbstractRoutingDataSource#determineCurrentLookupKey()来达到数据源动态切换的目的。 网上有很的文章可以获取具体方法,就不在讲了。 项目中需要用到多数据源MySQL和SQL...
  • 超简单的 springboot 多数据源切换

    千次阅读 2019-03-31 00:28:12
    spring-boot-stater-multiple-datasource spring boot 多数据源启动类 ...在项目开发中经常会遇见同一个项目中使用数据源的场景,在使用时我们需要对数据源进行切换,某些指定的方法访问特定的数据源。...
  • 最近项目需要指出多数据源,同时支持事务回滚,这里记录一下 1、多数据源方式介绍 主要方式有以下两种: 通过配置个SqlSessionFactory 来实现多数据源,这么做的话,未免过于笨重,而且无法实现动态添加数据源...
  • 在实现方法或mapper方法上加@Transactional(propagation= Propagation.NEVER)注解 一、@Transactional 注解使用 1. @Transactional 注解只能用在public 方法上,如果用在protected或者private的方法上,不会报错,...
  • /** * 数据库标识 */ public enum DataSourceKey { /** * Master data source key. */ master, /** * Slave alpha data source key. */ slave, }
  • SpringBoot多数据源切换案例(附源码)

    千次阅读 2019-08-09 13:35:17
    2.1 实现多数据源 根据网上的大部分人的分享,我大概理清了思路,大致是这样: 1.写一个Holder通过改变ThreadLocal来直接修改数据源的名称 2.写一个注解,再在aop里配置一下,需要切换时通过注解来完成 这两...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,263
精华内容 4,905
关键字:

springboot多数据源切换

spring 订阅