springboot integrates mybatis and sets up multiple data sources

Springboot is now more popular than spring because it is simple, fast and convenient. Springboot was originally designed to simplify the configuration of spring by integrating new functionality faster in development, simplifying or reducing related configurations.Springboot is based on convention over configuration.All frameworks are integrated and springboot can be considered a collection of frameworks.
Let's take a look at the description of springboot features on the spring website:
1. Create a stand-alone Spring application
2. Embed Tomcat, Jetty, or Undertow directly (no WAR file needs to be deployed)
3. Provide self-righteous "starter" dependencies to simplify build configuration
4. Automatically configure Spring and third-party libraries whenever possible
5. Provide production ready functionality such as measurement, health check, and external configuration
6. There is no code generation at all and no XML configuration required (emphasis)

Today, let's talk about springboot integration with mybatis.

1. Setup of springboot project

1. Creation of springboot project

2.springboot Jump Page, which is similar to spring here.

    @RestController
    public class HelloController {

        @RequestMapping(value = "/hello")
        public String hello(){
            return "index";
        }
    }
    The returned "index" here defaults to resources/static.
When springboot starts, we can see these two lines: Tomcat initialized with port(s): 8080 (http) This line indicates that the default port for springboot is 8080.
You can also configure it in application.propertices (application.yml): server: port:8088 Starting Servlet engine: [Apache Tomcat/9.0.31] This line describes the version of tomcat built into springboot.

After launching the springboot project like this, type localhost:8080/hello in the browser address bar.You can open a page.

2. springboot integration mybatis

This article uses a more concise application.yml file instead of the application.properties file.Delete the original application.properties file in the resource folder and create the application.yml configuration file (Note: Actually, the application.yml file will be parsed into application.properties at the bottom of SpringBoot).
There is no difference between.yml and.properties except that yml is hierarchically divided and note that there is a space after the colon.
Instead of configuring mybatis with mybatisConfig.xml, use the @MapperScan annotation here.

1. Configure the data source in the application.yml configuration file.

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. Configure the mapper path for mybaits

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

3.mapper interface

  public interface UserMapper {

          /***
           * Query users based on primary key id
           * @param id
           * @return
           */
          User selectByPrimaryKey(Integer id);
  }  

4.user entities are not mentioned here. This is easy
5. Create a mapping/UserMapper.xml file under resources, where the path corresponds to the mapper path of mybatis configured in the second section above.The namespace of mapper.xml is the full class name of the mapper class.

<?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>
     <!--Query values based on primary key-->
     <select id="selectByPrimaryKey" parameterType="java.lang.Integer"  resultMap="baseResultMap">
           select * from T_USER where id = #{id}
     </select>

</mapper>

6. Test classes for mybatis

@SpringBootTest(classes = SpringbootdemoApplication.class)
@RunWith(SpringRunner.class)//Let the test run on Spring testing environment
public class MybatisTest {

     @Resource
     private UserMapper userMapper;

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

* springboot integration mybatis is complete here.It's that simple.

Configuring mybatis multiple data sources

Configuring MySQL multiple data sources

       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. Since there are multiple data sources, the default data source component needs to be disabled on the pringboot start class (*Application.java)

  //ProhibitedUse default data source component
   @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

3. You need to create your own component for a dynamic data source, where I created the mybatisConfig.java class;

          @Configuration
          @MapperScan(basePackages = "cn.seven.demo.dao")//Scanning DAO Package for
          @Slf4j
          public class MybatisConfig {

              /**
               * Create master data source
               * @return
               */
              @Bean("master")
              @Primary //set priority
              @ConfigurationProperties("spring.datasource.master") //Configuration Property File
              public DataSource master(){
                  return DataSourceBuilder.create().build();//builder Builder pattern
              }

              /**
               * Create From Data Source
               * @return
               */
              @Bean("slave")
              @Primary
              @ConfigurationProperties("spring.datasource.slave")
              public DataSource slave(){
                  return DataSourceBuilder.create().build();
              }

              /**
               * Generate a custom data source
               * @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());
                  //take master Data source as specified data source
                  dynamicDataSource.setDefaultDataSource(master());
                  //take master and slave Data source as specified data source
                  dynamicDataSource.setDataSource(mapDataSource);
                  return dynamicDataSource;
              }

              @Bean
              public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException {
                  SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
                  //Configure the data source, where it is configured as critical, if it is not dynamicDataSource Switching as a data source is not possible
                  sessionFactoryBean.setDataSource(dynamicDataSource());
                  //scanning model-entity Package for
                  sessionFactoryBean.setTypeAliasesPackage("cn.seven.demo.entity");
                  //Scan Mapping File
                  PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
                  sessionFactoryBean.setMapperLocations(pathMatchingResourcePatternResolver.getResources("classpath:mapping/*.xml"));
                  return sessionFactoryBean;
              }

              /**
               * Configure transaction management by adding the @Transactional annotation to the method header when using transactions
               * @return
               */
              @Bean
              public PlatformTransactionManager transactionManager(){
                  return new DataSourceTransactionManager(dynamicDataSource());
              }

       }

4. Annotation interfaces for data sources

@Target({ElementType.METHOD,ElementType.TYPE,ElementType.PARAMETER})//Set the scope of the note
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {

    String value() default "master";
}

5. Custom Dynamic Data Sources

public class DynamicDataSource extends AbstractRoutingDataSource {
    /**
     * If you don't want the data source to load when you start the configuration, you can customize this method to read and return the data source from anywhere you want.
     * For example, read the data source information from the database, file, external interface, and so on, and eventually return a DataSource implementation class object.
     * @return
     */
    @Override
    protected DataSource determineTargetDataSource() {
        return super.determineTargetDataSource();
    }

    /**
     * If you want all data sources to load when you start the configuration, customize this method by setting the data source key value to switch data sources
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceKey();
    }

    /**
     * Set Default Data Source
     * @param defaultDataSource
     */
    public void setDefaultDataSource(Object defaultDataSource){
        super.setDefaultTargetDataSource(defaultDataSource);
    }

    /**
     * Shezhu Data Source
     * @param dataSource
     */
    public void setDataSource(Map<Object,Object> dataSource){
        super.setTargetDataSources(dataSource);
        //Will be the source of the data key Placed in the context of the data source key Collection, used to determine whether a data source is valid when switching
        DynamicDataSourceContextHolder.addDataSourceKey(dataSource.keySet());
    }
}

6. Dynamic Data Source Context

public class DynamicDataSourceContextHolder {

    /**
     * Local thread for storing data sources
     */
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(){
        /**
         * Speak about master data source key as default data source key
         * @return
         */
        @Override
        protected String initialValue() {
           // return super.initialValue();//
            return "master";
        }
    };

    /**A key collection of data sources used to determine the existence of data sources when switching*/
    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);
    }

    /**
     * Reset Data Source
     */
    public static void cleanDataSource(){
        contextHolder.remove();
    }

    /**
     * Determine whether to include a data source
     * @param key key of data source
     * @return yes no
     */
    public static boolean containDataSourceKey(String key){
        return dataSourceKey.contains(key);
    }

    /**
     * Add data source key to support adding more than one, so collection is required
     * @param keys Data source key
     * @return
     */
    public static boolean addDataSourceKey(Collection<? extends Object> keys){
        return dataSourceKey.add(keys);
    }
}

7. Tangent classes for dynamic data sources

@Aspect
@Order(-1) //Priority over transaction annotation execution
@Component
@Slf4j
public class DynamicDataSourceAspect {

    @Before("@annotation(dataSource)")
    public void switchDataSource(JoinPoint point,DataSource dataSource){
        if(!DynamicDataSourceContextHolder.containDataSourceKey(dataSource.value())){
            System.out.println("Database mismatch : "+ dataSource.value());
        }else{
            System.out.println("Database Switching : "+ dataSource.value());
            DynamicDataSourceContextHolder.setDataSourceKey(dataSource.value());
        }
    }

    /**
     *  Empty Data Source
     * @param point
     * @param dataSource
     */
    @After("@annotation(dataSource)")
    public void restoreDataSource(JoinPoint point,DataSource dataSource){
        DynamicDataSourceContextHolder.cleanDataSource();
        System.out.println("Database connection empty:"+dataSource.value());
    }
}

8. Note the settings on the query method of the mapper interface userMapper: @DataSource("slave"), since our default database is master, we need to set it here as slave;

/***
 * Configure the representation after the annotation for multiple data sources
 * @param id
 * @return
 */
 @DataSource("slave")
 User selectByPrimaryKey(Integer id);
Also because the code to scan the map file was written in mybaitsConfig: //Scan map file PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver(); sessionFactoryBean.setMapperLocations(pathMatchingResourcePatternResolver.getResources("classpath:mapping/*.xml")); Therefore, you need to delete the path previously set in the yml file to read the mapper.xml file.

9. Use the above test class tests

At this point, springboot has finished integrating mybatis and setting up multiple data sources.

Welcome to download the source code: https://files.cnblogs.com/files/pluto-charon/springbootdemo.rar

Tags: Java SpringBoot Mybatis Spring xml

Posted on Sun, 22 Mar 2020 13:09:25 -0400 by BornForCode