springboot动态切换数据源

1.新建springboot项目

2.修改application.yml 如下,有两个数据源jdbc 和jdbc2

#the first datasource
jdbc:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test1?useUnicode=true&charaterEncoding=utf-8
    serverName: 127.0.0.1
    username: root
    password: root
#the second datasource
jdbc2:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test2?useUnicode=true&charaterEncoding=utf-8
    serverName: 127.0.0.1
    username: root
    password: root

# SPRING PROFILES
spring:
    # HTTP ENCODING
    http:
        encoding.charset: UTF-8
        encoding.enable: true
        encoding.force: true
# MyBatis
mybatis:
    typeAliasesPackage: com.niezheng,datasource.entity
    mapperLocations: classpath:/mybatis/*Mapper.xml



3.新建数据库枚举类型,数据库为test1 和test2

package com.niezheng.datasource.common;

/**
 * @Author: niezheng
 * @Description:  列举数据源的key
 * @Date: Create in 12:18 2017/12/19
 * @Modified By:
 */
public enum  DataBaseType {
    test1,test2
}


4.新建DatabaseContextHolder类

package com.niezheng.datasource.common;

/**
 * @Author: niezheng
 * @Description:   作用:1、保存一个线程安全的DatabaseType容器
 *                         2.构建一个DatabaseType容器,并提供了向其中设置和获取DatabaseType的方法
 * @Date: Create in 12:20 2017/12/19
 * @Modified By:
 */
public class DatabaseContextHolder {
    private static final ThreadLocal<DataBaseType> contextHolder = new ThreadLocal<DataBaseType>()
    {
        @Override
        protected DataBaseType initialValue() {
            return DataBaseType.test1;
        }
    };

    public static void setDatabaseType(DataBaseType type) {
        contextHolder.set(type);
    }

    public static DataBaseType getDatabaseType() {
        return contextHolder.get();
    }
}

5.新建DynamicDataSource类

package com.niezheng.datasource.common;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
 * @Author: niezheng
 * @Description:  使用DatabaseContextHolder获取当前线程的DatabaseType
 * @Date: Create in 12:27 2017/12/19
 * @Modified By:
 */
public class DynamicDataSource extends AbstractRoutingDataSource  {
    @Override
    protected Object determineCurrentLookupKey() {
        return DatabaseContextHolder.getDatabaseType();
    }
}

6.新建MyBatisConfig类

package com.niezheng.datasource.common;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @Author: niezheng
 * @Description:
 * @Date: Create in 14:24 2017/12/19
 * @Modified By:
 */
@Configuration
@MapperScan(basePackages = "com.niezheng.datasource.mapper")
public class MyBatisConfig {
    /**
     * 创建数据源
     * @return
     * @throws Exception
     */
    @Primary
    @Bean("test1DataSource")
    @ConfigurationProperties(prefix = "jdbc")
    public DataSource test1DataSource() throws Exception {
        return DataSourceBuilder.create().build();
    }

    @Bean("test2DataSource")
    @ConfigurationProperties(prefix = "jdbc2")
    public DataSource test2DataSource() throws Exception {
        return DataSourceBuilder.create().build();
    }

    /**
     * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,热不是让@autowire报错
     * @Qualifier  根据名称进行注入,通常是在具有相同的多个类型的实例的一个注入,(例如有多个DataSource类型的实例)
     * @param myTestDbDataSource
     * @param myTestDb2DataSource
     * @return
     */
    @Bean
    public DynamicDataSource dataSource(@Qualifier("test1DataSource") DataSource myTestDbDataSource,
                                        @Qualifier("test2DataSource") DataSource myTestDb2DataSource){
        Map<Object,Object> targetDataSource = new HashMap<>();
        targetDataSource.put(DataBaseType.test1,myTestDbDataSource);
        targetDataSource.put(DataBaseType.test2,myTestDb2DataSource);
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSource);
        dynamicDataSource.setDefaultTargetDataSource(myTestDbDataSource);
        return dynamicDataSource;
    }

    /**
     * 根据数据源创建SqlSessionFactory
     * @param dynamicDataSource
     * @return
     * @throws Exception
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource) throws Exception {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        /**指定数据源(必须有否则报错)*/
        sessionFactoryBean.setDataSource(dynamicDataSource);
        // 下边两句仅仅用于*.xml文件,如果整个持久层操作不需要使用到xml文件的话(只用注解就可以搞定),则不加
    /*    sessionFactoryBean.setTypeAliasesPackage(env.getProperty("mybatis.typeAliasesPackage"));
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapperLocations")));*/
        return sessionFactoryBean.getObject();
    }

    /**
     * 配置事务管理器
     * @param dynamicDataSource
     * @return
     */
    @Bean
    public DataSourceTransactionManager transactionManager(DynamicDataSource dynamicDataSource){
        return new DataSourceTransactionManager(dynamicDataSource);
    }
    
}

7.使用AOP动态切换数据源

package com.niezheng.datasource.Aspect;

import com.niezheng.datasource.common.DataBaseType;
import com.niezheng.datasource.common.DatabaseContextHolder;
import com.niezheng.datasource.dao.ShopDao;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @Author: niezheng
 * @Description:
 * @Date: Create in 16:04 2017/12/19
 * @Modified By:
 */
@Aspect
@Component
public class DataSourceAspect {

    /**
     * 使用空方法定义切点表达式
     */
    @Pointcut("execution(* com.niezheng.datasource.dao.*.*(..))")
    public void declareJointPointExpression() {
    }

    @Before("declareJointPointExpression()")
    public void setDataSourceKey(JoinPoint point){
        if(point.getTarget() instanceof ShopDao){
            DatabaseContextHolder.setDatabaseType(DataBaseType.test1);
        }else {
            DatabaseContextHolder.setDatabaseType(DataBaseType.test2);
        }
    }
}



8.新建test1库 和test2库查询

package com.niezheng.datasource.mapper;

import com.niezheng.datasource.entity.Person;
import com.niezheng.datasource.entity.Shop;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

/**
 * @Author: niezheng
 * @Description:
 * @Date: Create in 17:02 2017/12/19
 * @Modified By:
 */
public interface PersonMapper {
    @Select("SELECT * FROM t_person WHERE id = #{id}")
    @Results(value = { @Result(id = true, column = "id", property = "id"),
            @Result(column = "person_name", property = "personName") })
    public Person getPerson(@Param("id") int id);
}



package com.niezheng.datasource.mapper;

import com.niezheng.datasource.entity.Shop;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

/**
 * @Author: niezheng
 * @Description:
 * @Date: Create in 15:40 2017/12/19
 * @Modified By:
 */
public interface ShopMapper {
    @Select("SELECT * FROM t_shop WHERE id = #{id}")
    @Results(value = { @Result(id = true, column = "id", property = "id"),
            @Result(column = "shop_name", property = "shopName") })
    public Shop getShop(@Param("id") int id);
}



9.新建controller层进行访问

package com.niezheng.datasource.controller;

import com.niezheng.datasource.entity.Person;
import com.niezheng.datasource.entity.Shop;
import com.niezheng.datasource.service.PersonService;
import com.niezheng.datasource.service.ShopService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: niezheng
 * @Description:
 * @Date: Create in 16:17 2017/12/19
 * @Modified By:
 */
@RestController
@RequestMapping("datasource")
public class ShopController {
    @Autowired
    private ShopService shopService;

    @Autowired
    private PersonService personService;

    @RequestMapping("/shop")
    public Shop getShop(){
        Shop shop = shopService.getShop(1);
        return shop;
    }

    @RequestMapping("/person")
    public Person getPerson(){
        Person person = personService.getPerson(1);
        return person;
    }
}

10.新建数据库test1 和test2

   

11.启动项目浏览器访问

    


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值