springboot使用mybatis多数据源和动态数据源

  1. 多数据源
  2. 动态数据源

多数据源

在pom中导入依赖

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

多数据源在配置文件时要加入你所需要的多个数据源的信息

mybatis.config-location=classpath:mybatis/mybatis-config.xml

spring.datasource.one.jdbc-url=jdbc:mysql://localhost:3306/test1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.one.username=root
spring.datasource.one.password=root
spring.datasource.one.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.two.jdbc-url=jdbc:mysql://localhost:3306/test2?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.two.username=root
spring.datasource.two.password=root
spring.datasource.two.driver-class-name=com.mysql.cj.jdbc.Driver

为两个数据源创建不同的mapper包路径
例如:原来的单数据源将接口文档建在mapper包下,而多数据源建在mapper包下在分出来one包和two包,放置接口文件,对应的映射文件也是如此。


配置第⼀个数据源,新建 DataSource1Config。值得注意的是在配置数据源时要用@Primary指定主数据源

@Configuration
@MapperScan(basePackages = "com.neo.mapper.one", sqlSessionTemplateRef  = "oneSqlSessionTemplate")
public class DataSource1Config {

    @Bean(name = "oneDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.one")
    @Primary
    public DataSource testDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "oneSqlSessionFactory")
    @Primary
    public SqlSessionFactory testSqlSessionFactory(@Qualifier("oneDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/one/*.xml"));
        return bean.getObject();
    }

    @Bean(name = "oneTransactionManager")
    @Primary
    public DataSourceTransactionManager testTransactionManager(@Qualifier("oneDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "oneSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("oneSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

}

basePackages 指明 Mapper 地址。
sqlSessionTemplateRef 指定 Mapper 路径下注⼊的 sqlSessionTemplate。


第⼆个数据源配置
DataSource2Config 的配置和上⾯类似,⽅法上需要去掉 @Primary 注解,替换对应的数据源和 Mapper 路
径即可。下⾯是 DataSource2Config

@Configuration
@MapperScan(basePackages = "com.neo.mapper.two", sqlSessionTemplateRef  = "twoSqlSessionTemplate")
public class DataSource2Config {

    @Bean(name = "twoDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.two")
    public DataSource testDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "twoSqlSessionFactory")
    public SqlSessionFactory testSqlSessionFactory(@Qualifier("twoDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/two/*.xml"));
        return bean.getObject();
    }

    @Bean(name = "twoTransactionManager")
    public DataSourceTransactionManager testTransactionManager(@Qualifier("twoDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "twoSqlSessionTemplate")
    public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("twoSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

}

接下来就是注入

@Autowired
 private User1Mapper user1Mapper;
 @Autowired
 private User2Mapper user2Mapper;

动态数据源

使用spring aop来动态切换数据源
Spring动态切换数据库的原理是通过继承AbstractRoutingDataSource重写determineCurrentLookupKey()方法,来决定使用那个数据库。在开启事务之前,通过改变lookupKey来达到切换数据源目的。

先写DataSourceContextHolder用来保存当前线程的数据库源。

public class DataSourceContextHolder {

    /**
     * 默认数据源
     */
    public static final String DEFAULT_DS = "masterRds";

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    // 设置数据源名
    public static void setDB(String dbType) {
        contextHolder.set(dbType);
    }

    // 获取数据源名
    public static String getDB() {
        return (contextHolder.get());
    }

    // 清除数据源名
    public static void clearDB() {
        contextHolder.remove();
    }

}

DynamicDataSource

@Component
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDB();
    }

}

配置数据源
DataSourceConfig

@Component
@Configuration
public class DataSourceConfig {

    @Value("${spring.datasource.master.url}")
    String masterUrl;
    @Value("${spring.datasource.master.username}")
    String masterUsername;
    @Value("${spring.datasource.master.password}")
    String masterPassword;
    @Value("${spring.datasource.master.driver-class-name}")
    String masterDriverClassName;

    @Bean(name = "masterRds")
    public DataSource masterDs() {
        DruidDataSource datasource1 = new DruidDataSource();
        datasource1.setUrl(masterUrl);
        datasource1.setUsername(masterUsername);
        datasource1.setPassword(masterPassword);
        datasource1.setDriverClassName(masterDriverClassName);
        return datasource1;
    }

    @Value("${spring.datasource.cluster-rds.url}")
    String clusterUrl;
    @Value("${spring.datasource.cluster-rds.username}")
    String clusterUsername;
    @Value("${spring.datasource.cluster-rds.password}")
    String clusterPassword;
    @Value("${spring.datasource.cluster-rds.driver-class-name}")
    String clusterDriverClassName;

    @Bean(name = "clusterRds")
    public DataSource clusterRds() {
        DruidDataSource datasource1 = new DruidDataSource();
        datasource1.setUrl(clusterUrl);
        datasource1.setUsername(clusterUsername);
        datasource1.setPassword(clusterPassword);
        datasource1.setDriverClassName(clusterDriverClassName);
        return datasource1;
    }

    @Value("${spring.datasource.user-datasouce.url}")
    String userUrl;
    @Value("${spring.datasource.user-datasouce.username}")
    String userUsername;
    @Value("${spring.datasource.user-datasouce.password}")
    String userPassword;
    @Value("${spring.datasource.user-datasouce.driver-class-name}")
    String userDriverClassName;

    @Bean(name = "userDs")
    public DataSource userDs() {
        DruidDataSource datasource1 = new DruidDataSource();
        datasource1.setUrl(userUrl);
        datasource1.setUsername(userUsername);
        datasource1.setPassword(userPassword);
        datasource1.setDriverClassName(userDriverClassName);
        return datasource1;
    }



    /**
     * 动态数据源: 通过AOP在不同数据源之间动态切换
     *
     * @return
     */
    @Primary
    @Bean(name = "dynamicDataSource")
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 默认数据源
        dynamicDataSource.setDefaultTargetDataSource(masterDs());
        // 配置多数据源
        Map<Object, Object> dsMap = Maps.newHashMap();
        dsMap.put("masterRds", masterDs());
        dsMap.put("clusterRds", clusterRds());
        dsMap.put("userDs",userDs());

        dynamicDataSource.setTargetDataSources(dsMap);
        return dynamicDataSource;
    }

    /**
     * 配置@Transactional注解事物
     *
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}

使用aop来进行切换

定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface DS {
    String value() default "masterRds";
}
@Aspect
@Component
public class DynamicDataSourceAspect {

    @Before("@annotation(ds)")
    public void beforeSwitchDS(JoinPoint point, DS ds) {
        //获得当前访问的class
        Class<?> className = point.getTarget().getClass();
        //获得访问的方法名
        String methodName = point.getSignature().getName();
        //得到方法的参数的类型
        Class[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();
        String dataSource = DataSourceContextHolder.DEFAULT_DS;
        try {
            // 得到访问的方法对象
            Method method = className.getMethod(methodName, argClass);
            // 判断是否存在@DS注解
            if (method.isAnnotationPresent(DS.class)) {
                DS annotation = method.getAnnotation(DS.class);
                // 取出注解中的数据源名
                dataSource = annotation.value();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 切换数据源
        DataSourceContextHolder.setDB(dataSource);
    }

    @AfterReturning("@annotation(ds)")
    public void afterSwitchDS(JoinPoint point, DS ds) {
        String db = DataSourceContextHolder.getDB();
        DataSourceContextHolder.clearDB();
        DataSourceContextHolder.setDB(DataSourceContextHolder.DEFAULT_DS);
        String db1 = DataSourceContextHolder.getDB();
    }
}

使用

  @DS("clusterRds")
    public int selectNum() {
        return authCenterMapper.selectNum();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值