springboot整合mybatis并设置多数据源

2020-03-22 16:06:24来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

springboot整合mybatis并设置多数据源

现在springboot的火热程度已经超过了spring了,因为springboot简单快速方便,springboot的基础是“约定大于配置”。整合了所有的框架,就可以把springboot当作一个框架集合。
我们来看看spring官网对springboot的特点的描述:
     1. 创建独立的Spring应用程序
     2.直接嵌入Tomcat、Jetty或Undertow(不需要部署WAR文件)
     3.提供自以为是的“starter”依赖项以简化构建配置
     4.尽可能自动配置Spring和第三方库
     5.提供生产就绪功能,如度量、运行状况检查和外部化配置
     6.完全没有代码生成,也不需要XML配置(重点)

最近在学习springboot。今天来介绍下springboot整合mybatis。

一.springboot项目的搭建

  1.springboot项目的创建

    2.springboot跳转页面,这里跟spring是一样的。

    @RestController
    public class HelloController {

        @RequestMapping(value = "/hello")
        public String hello(){
            return "index";
        }
    }
    这里的返回的"index"默认位于resources/static下的。
当springboot启动的时候,我们可以看到这两行: Tomcat initialized with port(s):
8080 (http) 这一行说明springboot的默认端口为8080。也可以在application.propertices里面配置: server: port:8088 Starting Servlet engine: [Apache Tomcat/9.0.31] 这一行说明springboot内置的tomcat的版本。

   这样启动springboot项目后,在浏览器地址栏上输入localhost:8080/hello。就可以打开一个页面。

二.springboot整合mybatis

     本文不使用application.properties文件 而使用更加简洁的application.yml文件。将resource文件夹下原有的application.properties文件删除,创建application.yml配置文件(备注:其实SpringBoot底层会把application.yml文件解析为application.properties),
     .yml和.properties没什么区别,差异在于yml会有层级的划分,并且注意在冒号:后面要有空格.
     在这里是使用的@MapperScan注解来,而不是用的mybatisConfig.xml配置mybatis的。

    1.配置数据源,在application.yml的配置文件中。

spring:
   datasource:
      driver-class-class: com.mysql.jdbc.Driver
      ## type: com.zaxxer.hikari.HikariDataSource
      jdbcUrl: jdbc:mysql://localhost:3306/zj?serverTimezone=GMT%2B8
      username: root
      password: root

    2.配置mybaits的mapper路径

mybatis:
        mapper-locations: classpath:mapping/*.xml

   3.mapper接口

  public interface UserMapper {

          /***
           * 根据主键id查询用户
           * @param id
           * @return
           */
          User selectByPrimaryKey(Integer id);
  }  

    4.user的实体这里就不说了,这个很容易
    5.在resources下面创建一个mapping/UserMapper.xml文件,这里的路径是对应上面第二部配置的mybatis的mapper路径的。mapper.xml的namespace就是mapper类的全类名。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.seven.demo.dao.UserMapper">
     <resultMap id="baseResultMap" type="cn.seven.demo.entity.User">
          <id column="id" jdbcType="INTEGER" property="id"></id>
          <result column="realName" jdbcType="VARCHAR" property="realName"></result>
          <result column="username" jdbcType="VARCHAR" property="username"></result>
          <result column="sex" jdbcType="INTEGER" property="sex"></result>
     </resultMap>
     <!--根据主键查询值-->
     <select id="selectByPrimaryKey" parameterType="java.lang.Integer"  resultMap="baseResultMap">
           select * from T_USER where id = #{id}
     </select>

</mapper>

     6.mybatis的测试类

@SpringBootTest(classes = SpringbootdemoApplication.class)
@RunWith(SpringRunner.class)//让测试运行于Spring测试环境
public class MybatisTest {

     @Resource
     private UserMapper userMapper;

     @Test
     public void test(){
          User user = userMapper.selectByPrimaryKey(1);
          System.out.println(user);
     }
}

      到这里springboot整合mybatis就完成了。就是这么简单。

三.配置mybatis多数据源

     1. 配置MySQL多数据源

       spring:
            datasource:
              master:
                driver-class-class: com.mysql.jdbc.Driver
                type: com.zaxxer.hikari.HikariDataSource
                jdbcUrl: jdbc:mysql://localhost:3306/zj?serverTimezone=GMT%2B8
                username: root
                password: root
              slave:
                driver-class-class: com.mysql.jdbc.Driver
                type: com.zaxxer.hikari.HikariDataSource
                jdbcUrl: jdbc:mysql://localhost:3307/zj?serverTimezone=GMT%2B8
                username: root
                password: root

     2.由于是多数据源,所以在pringboot都启动类(*Application.java)上需要禁用默认得数据源组件

  //禁用默认的数据源组件
   @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

     3.需要自己创建一个动态数据源的组件,这里我创建的是mybatisConfig.java类;

          @Configuration
          @MapperScan(basePackages = "cn.seven.demo.dao")//扫瞄DAO的包
          @Slf4j
          public class MybatisConfig {

              /**
               * 创建主数据源
               * @return
               */
              @Bean("master")
              @Primary //设置优先级
              @ConfigurationProperties("spring.datasource.master") //配置属性文件
              public DataSource master(){
                  return DataSourceBuilder.create().build();//builder建造者模式
              }

              /**
               * 创建从数据源
               * @return
               */
              @Bean("slave")
              @Primary
              @ConfigurationProperties("spring.datasource.slave")
              public DataSource slave(){
                  return DataSourceBuilder.create().build();
              }

              /**
               * 生成自定义的数据源
               * @return
               */
              @Bean("dynamicDataSource")
              public DataSource dynamicDataSource(){
                  DynamicDataSource dynamicDataSource = new DynamicDataSource();
                  Map<Object,Object>  mapDataSource = new HashMap<Object,Object>(2);
                  mapDataSource.put("master",master());
                  mapDataSource.put("slave",slave());
                  //将master数据源作为指定的数据源
                  dynamicDataSource.setDefaultDataSource(master());
                  //将master和slave数据源作为指定的数据源
                  dynamicDataSource.setDataSource(mapDataSource);
                  return dynamicDataSource;
              }

              @Bean
              public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException {
                  SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
                  //配置数据源,此处配置为关键配置,如果没有将dynamicDataSource作为数据源则不能实现切换
                  sessionFactoryBean.setDataSource(dynamicDataSource());
                  //扫描model-entity的包
                  sessionFactoryBean.setTypeAliasesPackage("cn.seven.demo.entity");
                  //扫描映射文件
                  PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
                  sessionFactoryBean.setMapperLocations(pathMatchingResourcePatternResolver.getResources("classpath:mapping/*.xml"));
                  return sessionFactoryBean;
              }

              /**
               * 配置事务管理,使用事务时哎方法头部添加@Transactional注解即可
               * @return
               */
              @Bean
              public PlatformTransactionManager transactionManager(){
                  return new DataSourceTransactionManager(dynamicDataSource());
              }

       }

        4.数据源的注解接口

@Target({ElementType.METHOD,ElementType.TYPE,ElementType.PARAMETER})//设置注解的作用范围
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {

    String value() default "master";
}

     5.自定义的动态数据源

public class DynamicDataSource extends AbstractRoutingDataSource {
    /**
     * 如果不希望数据源在启动配置时就加载好,可以定制这个方法,从任何你希望的地方读取并返回数据源,
     * 比如从数据库,文件,外部接口等读取数据源信息,并最终返回一个DataSource实现类对象即可
     * @return
     */
    @Override
    protected DataSource determineTargetDataSource() {
        return super.determineTargetDataSource();
    }

    /**
     * 如果希望所有的数据源在启动配置时加载好,这里通过设置数据源key值来切换数据源,定制这个方法
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceKey();
    }

    /**
     * 设置默认的数据源
     * @param defaultDataSource
     */
    public void setDefaultDataSource(Object defaultDataSource){
        super.setDefaultTargetDataSource(defaultDataSource);
    }

    /**
     * 社渚数据源
     * @param dataSource
     */
    public void setDataSource(Map<Object,Object> dataSource){
        super.setTargetDataSources(dataSource);
        //将数据源的key放到数据源上下文的key集合中,用于切换时判断数据源是否有效
        DynamicDataSourceContextHolder.addDataSourceKey(dataSource.keySet());
    }
}

    6.动态数据源上下文

public class DynamicDataSourceContextHolder {

    /**
     * 用于存放数据源的本地线程
     */
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(){
        /**
         * 讲master数据源的key作为默认的数据源的key
         * @return
         */
        @Override
        protected String initialValue() {
           // return super.initialValue();//
            return "master";
        }
    };

    /**数据源的key集合,用于切换时判断数据源是否存在*/
    private static List<Object> dataSourceKey = new ArrayList<Object>();

    /**
     * @return the value of contextHolder
     */
    public static ThreadLocal<String> getContextHolder() {
        return contextHolder;
    }

    /**
     * @return the value of dataSourceKey
     */
    public static List<Object> getDataSourceKey() {
        return dataSourceKey;
    }

    /**
     * Sets the dataSourceKey
     *
     * @param dataSourceKey dataSourceKey
     */
    public static void setDataSourceKey(String dataSourceKey) {
        contextHolder.set(dataSourceKey);
    }

    /**
     * 重置数据源
     */
    public static void cleanDataSource(){
        contextHolder.remove();
    }

    /**
     * 判断是否包含数据源
     * @param key 数据源的key
     * @return yes no
     */
    public static boolean containDataSourceKey(String key){
        return dataSourceKey.contains(key);
    }

    /**
     * 添加数据源key,支持加多个,所以需要用collection
     * @param keys 数据源key
     * @return
     */
    public static boolean addDataSourceKey(Collection<? extends Object> keys){
        return dataSourceKey.add(keys);
    }
}

   7.  动态数据源的切面类

@Aspect
@Order(-1) //优先于事务注解执行
@Component
@Slf4j
public class DynamicDataSourceAspect {

    @Before("@annotation(dataSource)")
    public void switchDataSource(JoinPoint point,DataSource dataSource){
        if(!DynamicDataSourceContextHolder.containDataSourceKey(dataSource.value())){
            System.out.println("数据库不匹配 : "+ dataSource.value());
        }else{
            System.out.println("数据库切换 : "+ dataSource.value());
            DynamicDataSourceContextHolder.setDataSourceKey(dataSource.value());
        }
    }

    /**
     *  清空数据源
     * @param point
     * @param dataSource
     */
    @After("@annotation(dataSource)")
    public void restoreDataSource(JoinPoint point,DataSource dataSource){
        DynamicDataSourceContextHolder.cleanDataSource();
        System.out.println("数据库连接清空:"+dataSource.value());
    }
}

   8.注意mapper接口的userMapper的查询方法上设置:@DataSource("slave"),由于我们的默认数据库是master,所以这里需要设置成slave;

/***
 * 配置多数据源  注解后面的表示方法
 * @param id
 * @return
 */
 @DataSource("slave")
 User selectByPrimaryKey(Integer id);
同时由于在mybaitsConfig里写了扫描映射文件的代码:
//扫描映射文件 PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver(); sessionFactoryBean.setMapperLocations(pathMatchingResourcePatternResolver.getResources("classpath:mapping/*.xml")); 所以需要将之前在yml文件里设置的读取mapper.xml文件的路径删除。

   9.使用上面的测试类测试

   到这,springboot整合mybatis并设置多数据源就已经完成了。

   欢迎大家下载源码:https://files.cnblogs.com/files/pluto-charon/springbootdemo.rar

 


原文链接:https://www.cnblogs.com/pluto-charon/p/12549521.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:Netty源码分析——EventLoopGroup建立

下一篇:Dubbo之服务消费原理