Java实现多数据源的方式

Java实现多数据源的方式

文章目录

  • Java实现多数据源的方式
    • 一、利用Spring提供的类实现
      • 1)在yml文件当中配置多数据源
      • 2) 定义一个DataSourceConfig 配置类来配置两个数据源
      • 3)自定义一个类 来 继承 org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
      • 4) 添加一个根据注解设置的动态数据源
      • 5) 在service中使用指定的数据源
      • 二、利用mybatis层次实现
        • 1)分别配置两个配置源,单独配置
        • 2) 编写WMyBatisConfig配置文件
        • 3) 编写RMyBatisConfig 配置文件
        • 4) 在serviceImpl实现层 单独调用配置的Mapper代理类
        • 三、Spring自动化支持
          • 1) 引入pom依赖
          • 2) 添加配置文件
          • 3)在service层利用注解==@DS实现==

            一、利用Spring提供的类实现

            1)在yml文件当中配置多数据源

            spring:
              datasource:
                type: com.alibaba.druid.pool.DruidDataSource
                datasource1:
                  url: jdbc:mysql://127.0.0.1:3306/datasource1?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF8&useSSL=false
                  username: root
                  password: root
                  initial-size: 1
                  min-idle: 1
                  max-active: 20
                  test-on-borrow: true
                  driver-class-name: com.mysql.cj.jdbc.Driver
                datasource2:
                  url: jdbc:mysql://127.0.0.1:3306/datasource2?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF8&useSSL=false
                  username: root
                  password: root
                  initial-size: 1
                  min-idle: 1
                  max-active: 20
                  test-on-borrow: true
                  driver-class-name: com.mysql.cj.jdbc.Driver
            

            2) 定义一个DataSourceConfig 配置类来配置两个数据源

            @Configuration
            public class DataSourceConfig { @Bean
                @ConfigurationProperties(prefix = "spring.datasource.datasource1")
                public DataSource dataSource1() { // 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSource
                    return DruidDataSourceBuilder.create().build();
                }
                @Bean
                @ConfigurationProperties(prefix = "spring.datasource.datasource2")
                public DataSource dataSource2() { // 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSource
                    return DruidDataSourceBuilder.create().build();
                }
                /* @Bean
                public Interceptor dynamicDataSourcePlugin(){
                    return new DynamicDataSourcePlugin();
                }
            */
                @Bean
                public DataSourceTransactionManager transactionManager1(DynamicDataSource dataSource){ DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
                    dataSourceTransactionManager.setDataSource(dataSource);
                    return dataSourceTransactionManager;
                }
                @Bean
                public DataSourceTransactionManager transactionManager2(DynamicDataSource dataSource){ DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
                    dataSourceTransactionManager.setDataSource(dataSource);
                    return dataSourceTransactionManager;
                }
            }
            

            3)自定义一个类 来 继承 org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

            ** 在类里面注入分别注入两个数据源**

            @Component
            @Primary   // 将该Bean设置为主要注入Bean
            public class DynamicDataSource extends AbstractRoutingDataSource {// 当前使用的数据源标识
                public static ThreadLocal name=new ThreadLocal<>();
              // 写
                @Autowired
                DataSource dataSource1;
                // 读
                @Autowired
                DataSource dataSource2;
                    // 返回当前数据源标识
                @Override
                protected Object determineCurrentLookupKey() { return name.get();
                        }
                }
              	// ** 在这个类初始化完成之后,进行数据源的注入**
                   // 当前使用的数据源标识
                public static ThreadLocal name=new ThreadLocal<>();
                @Override
                public void afterPropertiesSet() { // 为targetDataSources初始化所有数据源
                    Map targetDataSources=new HashMap<>();
                    targetDataSources.put("W",dataSource1);
                    targetDataSources.put("R",dataSource2);
                    super.setTargetDataSources(targetDataSources);
                    // 为defaultTargetDataSource 设置默认的数据源
                    super.setDefaultTargetDataSource(dataSource1);
                    super.afterPropertiesSet();
                }
            

            4) 添加一个根据注解设置的动态数据源

            @Component
            @Aspect
            public class DynamicDataSourceAspect implements Ordered { // 前置
                @Before("within(com.tuling.dynamic.datasource.service.impl.*) && @annotation(wr)")
                public void before(JoinPoint point, WR wr){ String name = wr.value();
                    DynamicDataSource.name.set(name);
                    System.out.println(name);
                }
                @Override
                public int getOrder() { return 0;
                }
                // 环绕通知
            }
            

            5) 在service中使用指定的数据源

            @Service
            public class FriendImplService implements FriendService { @Autowired
                FriendMapper friendMapper;
                @Override
                @WR("R")        // 库2
                public List list() {//        DynamicDataSource.name.set("R");
                    return friendMapper.list();
                }
                @Override
                @WR("W")        // 库1
                public void save(Friend friend) {//        DynamicDataSource.name.set("W");
                    friendMapper.save(friend);
                }
            }
            

            上面采用注解的方式就是,其实是利用切面进行数据源的设置,和注释的注释方式类似

            二、利用mybatis层次实现

            1)分别配置两个配置源,单独配置

            2) 编写WMyBatisConfig配置文件

            @Configuration
            // 继承mybatis:
            // 1. 指定扫描的mapper接口包(主库)
            // 2. 指定使用sqlSessionFactory是哪个(主库)
            @MapperScan(basePackages = "com.datasource.dynamic.mybatis.mapper.w",
                    sqlSessionFactoryRef="wSqlSessionFactory")
            public class WMyBatisConfig { @Bean
                @ConfigurationProperties(prefix = "spring.datasource.datasource1")
                public DataSource dataSource1() { // 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSource
                    return DruidDataSourceBuilder.create().build();
                }
                @Bean
                @Primary
                public SqlSessionFactory wSqlSessionFactory()
                        throws Exception { final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
                    // 指定主库
                    sessionFactory.setDataSource(dataSource1());
                    // 指定主库对应的mapper.xml文件
                    /*sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                            .getResources("classpath:mapper/order/*.xml"));*/
                    return sessionFactory.getObject();
                }
                @Bean
                @Primary
                public DataSourceTransactionManager wTransactionManager(){ DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
                    dataSourceTransactionManager.setDataSource(dataSource1());
                    return dataSourceTransactionManager;
                }
                @Bean
                public TransactionTemplate wTransactionTemplate(){ return new TransactionTemplate(wTransactionManager());
                }
            }
            

            3) 编写RMyBatisConfig 配置文件

            @Configuration
            // 继承mybatis:
            // 1. 指定扫描的mapper接口包(主库)
            // 2. 指定使用sqlSessionFactory是哪个(主库)
            @MapperScan(basePackages = "com.tuling.datasource.dynamic.mybatis.mapper.r",
                    sqlSessionFactoryRef="rSqlSessionFactory")
            public class RMyBatisConfig { @Bean
                @ConfigurationProperties(prefix = "spring.datasource.datasource2")
                public DataSource dataSource2() { // 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSource
                    return DruidDataSourceBuilder.create().build();
                }
                @Bean
                @Primary
                public SqlSessionFactory rSqlSessionFactory()
                        throws Exception { final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
                    // 指定主库
                    sessionFactory.setDataSource(dataSource2());
                    // 指定主库对应的mapper.xml文件
                    /*sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                            .getResources("classpath:mapper/r/*.xml"));*/
                    return sessionFactory.getObject();
                }
                @Bean
                public DataSourceTransactionManager rTransactionManager(){ DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
                    dataSourceTransactionManager.setDataSource(dataSource2());
                    return dataSourceTransactionManager;
                }
                @Bean
                public TransactionTemplate rTransactionTemplate(){ return new TransactionTemplate(rTransactionManager());
                }
            }
            

            4) 在serviceImpl实现层 单独调用配置的Mapper代理类

             @Autowired
                private RFriendMapper rFriendMapper;
                @Autowired
                private WFriendMapper wFriendMapper;
                // 读-- 读库
                @Override
                public List list() { return rFriendMapper.list();
                }
              // 保存-- 写库
                @Override
                public void saveW(Friend friend) { friend.setName("loulan");
                    wFriendMapper.save(friend);
                }
                // 保存-- 读库
                @Override
                public void saveR(Friend friend) { friend.setName("loulan");
                    rFriendMapper.save(friend);
                }
            

            三、Spring自动化支持

            1) 引入pom依赖

              com.baomidou dynamic-datasource-spring-boot-starter 3.5.0 

            2) 添加配置文件

            spring:
              datasource:
                dynamic:
                  #设置默认的数据源或者数据源组,默认值即为master
                  primary: master
                  #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
                  strict: false
                  datasource:
                    master:
                      url: jdbc:mysql://127.0.0.1:3306/datasource1?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF8&useSSL=false
                      username: root
                      password: root
                      initial-size: 1
                      min-idle: 1
                      max-active: 20
                      test-on-borrow: true
                      driver-class-name: com.mysql.cj.jdbc.Driver
                    slave_1:
                      url: jdbc:mysql://127.0.0.1:3306/datasource2?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF8&useSSL=false
                      username: root
                      password: root
                      initial-size: 1
                      min-idle: 1
                      max-active: 20
                      test-on-borrow: true
                      driver-class-name: com.mysql.cj.jdbc.Driver
            

            3)在service层利用注解==@DS实现==

            @Service
            public class FriendImplService implements FriendService { @Autowired
                FriendMapper friendMapper;
                @Override
                @DS("slave_1")  // 从库, 如果按照下划线命名方式配置多个  , 可以指定前缀即可(组名)
                public List list() { return friendMapper.list();
                }
                @Override
                @DS("master")
                public void save(Friend friend) { friendMapper.save(friend);
                }
                @DS("master")
                @DSTransactional
                public void saveAll(){ // 执行多数据源的操作
                }
            }