spring boot + mybatis 多数据源配置

本项目使用spring-boot + mybatis(tk.mybatis)

项目结构如下

项目结构

1、设置springboot 启动类,禁用自动数据源配置
@SpringBootApplication(scanBasePackages = "me.smallyellow.hhy", exclude = {DataSourceAutoConfiguration.class})
@EnableWebPath
public class Application {
    public static void main( String[] args ) {
        SpringApplication.run(Application.class, args);
    }
}
2、在config包下新建MyBatisConfig.java,对数据源进行相关设置,项目启动会走这个类,读取相关配置信息。
@Configuration
public class MyBatisConfig implements EnvironmentAware{

    private Environment environment;

    @Override
    public void setEnvironment(Environment arg0) {
        this.environment = arg0;
    }

     /**
     * 创建数据源(数据源的名称:方法名可以取为XXXDataSource(),XXX为数据库名称,该名称也就是数据源的名称)
     */
    @Bean
    public DataSource test1DataSource() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", environment.getProperty("test1-datasource.driverClassName"));
        props.put("url", environment.getProperty("test1-datasource.url"));
        props.put("username", environment.getProperty("test1-datasource.username"));
        props.put("password", environment.getProperty("test1-datasource.password"));
        return DruidDataSourceFactory.createDataSource(props);
    }

    @Bean
    public DataSource test2DataSource() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", environment.getProperty("test2-datasource.driverClassName"));
        props.put("url", environment.getProperty("test2-datasource.url"));
        props.put("username", environment.getProperty("test2-datasource.username"));
        props.put("password", environment.getProperty("test2-datasource.password"));
        return DruidDataSourceFactory.createDataSource(props);
    }

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

        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法
        dataSource.setDefaultTargetDataSource(test1DataSource);// 默认的datasource设置为myTestDbDataSource

        return dataSource;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer();
        scannerConfigurer.setBasePackage("me.smallyellow.hhy.mapper");
        Properties props = new Properties();
        props.setProperty("mappers", "tk.mybatis.mapper.common.Mapper");
        props.setProperty("IDENTITY", "MYSQL");
        props.setProperty("notEmpty", "true");
        scannerConfigurer.setProperties(props);
        return scannerConfigurer;
    }

    /**
     * 根据数据源创建SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource ds) throws Exception {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

        SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
        fb.setDataSource(ds);// 指定数据源(这个必须有,否则报错)
        // 下边两句仅仅用于*.xml文件,如果整个持久层操作不需要使用到xml文件的话(只用注解就可以搞定),则不加
        fb.setTypeAliasesPackage("me.smallyellow.hhy.model");// 指定基包
        fb.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml"));//

        return fb.getObject();
    }

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

3、设置application.properties

如上代码所示,我们test1-datasource.xx 和 test2-datasource.xx中读取了相关值。故而,我们需要在application.properties设置相关属性值。
test1-datasource.url=jdbc:mysql://localhost:3306/test
test1-datasource.username=root
test1-datasource.password=
test1-datasource.driverClassName=com.mysql.jdbc.Driver

test2-datasource.url=jdbc:mysql://localhost:3306/test2
test2-datasource.username=root
test2-datasource.password=
test2-datasource.driverClassName=com.mysql.jdbc.Driver
以上,成功配置多数据源
解释:MyBatisConfig 中 DynamicDataSource类进行了一个数据源路由的功能,DatabaseType里定义了数据源
public enum DatabaseType {
    test1,
    test2
}
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DatabaseContextHolder.getDatabaseType();
    }
}
再看DatabaseContextHolder 类,保证了始终只有一个DatabaseType容器
public class DatabaseContextHolder {
    private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>();

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

    public static void setDatabaseType(DatabaseType type) {
        contextHolder.set(type);
    }
}
至此,已经可以在service中对不同数据源中的数据进行操作了,但如果不是操作默认数据源,需要在操作之前设置数据源
    //数据源1
    public List<UserInfo> test() {
        List<UserInfo> list= userInfoMapper.selectAll();
        return list;
    }
    //数据源2
    public List<UserInfo> test2() {
        DatabaseContextHolder.setDatabaseType(DatabaseType.test2);
        List<UserInfo> list= userInfoMapper.selectAll();
        return list;
    }
但这样显得有点麻烦,所以,打算通过注解的方式进行配置
1、新建OtherDataSource.java 内容如下:
@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OtherDataSource {
    public DatabaseType dataType() default DatabaseType.test2;
}
2、我们需要在添加了这个注解的方法执行之前,先自动设置数据源,这里用到了切片的概念。新建DynamicDataSourceAspect.java
@Aspect
@Order(-10)//保证该AOP在@Transactional之前执行
@Component
public class DynamicDataSourceAspect {

    @Before("@annotation(otherDataSource)")
    public void changeDataSource(JoinPoint point, OtherDataSource otherDataSource){
       //获取当前的指定的数据源;
        DatabaseType dType = otherDataSource.dataType();
        DatabaseContextHolder.setDatabaseType(dType);
    }

}
添加完这两个类后,我们就可以使用注解的方式切换数据源了
    //数据源1
    public List<UserInfo> test() {
        List<UserInfo> list= userInfoMapper.selectAll();
        return list;
    }
    //数据源2
    @OtherDataSource
    public List<App> test2(){
        List<App> list = appMapper.selectAll();
        return list;
    }
详细代码–>前往github

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值