• Spring Boot 结合 Mybatis 解决多数据源的问题


         最近在研究Spring Cloud搭建微服务相关,对于一个庞大的系统,需要拆分为多个微服务,每个服务相当于一个模块,负责不同的事情,各司其职,当然,数据库之间也需要保持相对独立,这样就需要涉及到多个数据库,那么,如何使用Spring Boot配置多数据源呢?

         首先,我们需要一个自定义注解,命名为:DataSource

    @Retention(RetentionPolicy.RUNTIME)//将该注解定义在运行时级别
    @Target(ElementType.METHOD)//将该注解应用于方法上
    public @interface DataSource {

    String value() default "user";
    }
    然后创建数据源的类: DynamicDataSourceHolder
    public class DynamicDataSourceHolder {

    /**
    * 默认数据源
    *
    */
    public static final String DEFAULT_DATASOURCE = "user";

    public static final ThreadLocal<String> holder = new ThreadLocal<String>();

    public static void setDataSource(String name) {
    holder.set(name);
    }

    public static String getDataSouce() {
    return holder.get();
    }

    public static void clearDataSouce() {
    holder.remove();
    }

    }

    配置动态数据源的类: DynamicDataSource

       

    public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
    return DynamicDataSourceHolder.getDataSouce();
    }

    }

    然后我们生成数据源,创建 MybatisConfig类

      

    @Configuration
    @PropertySource("classpath:jdbc.properties") //引入配置文件jdbc.properties中的信息
    @MapperScan(basePackages ={"com.drive.dbuser.dao"} , sqlSessionFactoryRef = "sqlSessionFactory")   // 配置Mapper作用的位置
    public class MybatisConfig {

    @Bean(name = "user")
    @ConfigurationProperties(prefix = "user")
    public DataSource dataSourceUser(){
    return DataSourceBuilder.create().build();
    } //生成user数据源

    @Bean(name = "drive")
    @ConfigurationProperties(prefix = "drive")
    public DataSource dataSourceDrive(){
    return DataSourceBuilder.create().build();
    } //生成drive数据源


    @Bean(name = "order")
    @ConfigurationProperties(prefix = "order")
    public DataSource dataSourceOrder(){
    return DataSourceBuilder.create().build();
    } //生成order数据源

    @Bean(name = "dynamicDataSource")
    public DataSource dataSource(){
    DynamicDataSource dynamicDataSource = new DynamicDataSource();
    // 默认数据源---User
    dynamicDataSource.setDefaultTargetDataSource(dataSourceUser());
    // 配置多数据源
    Map<Object, Object> dataSourceMap = new HashMap(5);
    dataSourceMap.put("user", dataSourceUser());
    dataSourceMap.put("drive", dataSourceDrive());
    dataSourceMap.put("order", dataSourceOrder());
    dynamicDataSource.setTargetDataSources(dataSourceMap);
    return dynamicDataSource;
    } //配置多数据源

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource()); //
    //添加XML目录
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    try {
    factoryBean.setMapperLocations(resolver.getResources("classpath*:com/drive/dbuser/mapper/*.xml")); //生效的位置
    return factoryBean.getObject();
    } catch (Exception e) {
    e.printStackTrace();
    throw new RuntimeException(e);
    }
    }//创建Session工厂
    /* @Bean
    public SqlSessionTemplate sqlSessionTemplate() throws Exception { //SqlSessionTemplate 是 MyBatis-Spring 的核心。 这个类负责管理 MyBatis 的 SqlSession, 调用 MyBatis 的 SQL 方法
    SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory()); // 使用上面配置的Factory
    return template;
    }*/
    }

    我们来看一下 jdbc.properties的配置文件的信息:
    #用户服务库
    user.url=jdbc:mysql:***
    user.username=***
    user.password=***
    #打车服务库
    drive.url=
    drive.username=
    drive.password=
    #订单服务库
    order.url=
    order.username=
    order.password=

    user.driverClassName=com.mysql.jdbc.Driver
    drive.driverClassName=com.mysql.jdbc.Driver
    order.driverClassName=com.mysql.jdbc.Driver



    这样我们的多数据源都配置好了,那么如何调用呢,比如说我需要先去user数据库里查数据,然后再去drive数据库里添加数据,这样怎么动态的更换数据源呢?
    我们可以使用Spring 中的一大核心AOP,首先我们需要在application.properties文件中开启AOP
    spring.aop.auto=true
    #开启AOP

    然后创建 DataSourceAspect类,
    @Aspect
    @Component
    public class DataSourceAspect {

    @Pointcut("execution(* com.drive.dbuser.dao.*.*(..))")
    public void declareJointPointExpression() {
    }

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


    @After("declareJointPointExpression()")
    public void afterSwitchDS(JoinPoint point){
    DynamicDataSourceHolder.clearDataSouce();
    }

    }

    这时,我们再看一下关于Dao层的内容:
    @DataSource("user")
    List<CustomerVO> selectCustomer(CustomerVO customerVO);

    我们创建一个切面类,当我们调用Dao层之前,会首先查看在Mapper 接口上方法上的注解,并将它作为数据源,注入到DynamicDataSourceHolder中,这样,就可以实现动态切换数据源了。

    最后,我们在启动类上需要加上
    @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) //通过禁用指定的自动化配置来避免加载不必要的自动化配置
    @EnableConfigurationProperties //注解是用来开启对@ConfigurationProperties注解配置Bean的支持, 该注解告诉Spring Boot 使能支持@ConfigurationProperties:注解主要用来把properties配置文件转化为bean来使用

    当然,不要忘了在pom.xml中配置所需要的依赖:

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>



    <!-- Spring Boot Mybatis 依赖 -->
    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.1</version>
    </dependency>

    <!-- MySQL 连接驱动依赖 -->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.9</version>
    </dependency>

    <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.7.4</version>
    </dependency>

    <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.6.12</version>
    </dependency>

    <!--log4j-->
    <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.16</version>
    </dependency>

    好了,大功告成了,喜欢的朋友们记得关注我一下!





  • 相关阅读:
    dp的小理解
    POJ
    isolate-user-vlan隔离用户vlan的配置
    【mvrp多协议vlan注册协议给予三种注册方式的验证】
    【Commare中关于理论范畴和技术常用的技术术语】
    BGP映射和联盟
    filter-policy和AS-PATH-FILTER过滤BGP路由条目
    【路由过滤工具小结】
    【ISIS(中间系统到中间系统)路由链路状态信息协议初识】
    【poe设备加电配置】
  • 原文地址:https://www.cnblogs.com/hello-world-exception/p/9008437.html
Copyright © 2020-2023  润新知