SpringBoot+Mybatis implements multiple data sources + paging

1 Main dependency version

(1) SpringBoot 2.7.8

(2) Mybatis 2.2.2

(3)Pagehelper 1.3.0

(4)MySQL 8.0.26

(5)Oracle 11.2.0.3

2 Overview

(1) Two data sources are used here, namely MySQL and Oracle, and two databases are configured;

(2) Configure Mybatis and Pagehelper respectively for the above data sources (to implement paging);

(3) The data source, Mybatis, and paging are all custom configured, and their automatic configuration is turned off in the startup class.

3 SpringBoot integrates Mybatis to realize dynamic switching of multiple data sources

3.1 Integration and Configuration

3.1.1 Related dependencies pom.xml

<!-- mybatis-spring-boot-starter -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>
<!-- pagehelper-spring-boot-starter -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.3.0</version>
</dependency>
<!-- mysql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.26</version>
    <scope>runtime</scope>
</dependency>
<!-- oracle -->
<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc6</artifactId>
    <version>11.2.0.3</version>
</dependency>
<!--hutool -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.22</version>
</dependency>
<!-- yml file custom configuration, input prompts -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

3.1.2 application.yml configuration

Two data sources, db1 and db2, and paging are configured in the yml configuration. db1 corresponds to MySQL and db2 corresponds to Oracle. If paging is not required, the configuration under spring.pagehelper can be omitted.

spring:
  datasource:
    db1:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/studb?characterEncoding=UTF-8 & amp;useUnicode=true
      username: root
      password: root
    db2:
      driver-class-name: oracle.jdbc.driver.OracleDriver
      jdbc-url: jdbc:oracle:thin:@//localhost:1521/XE
      username: root
      password: root
#Paging configuration
  pagehelper:
    db1:
      dialect: mysql
      offsetAsPageNum: true
      rowBoundsWithCount: true
      reasonable: true
      supportMethodsArguments: true
      params: count=countSql;pageNum=pageNum;pageSize=pageSize;
    db2:
      dialect: oracle
      offsetAsPageNum: true
      rowBoundsWithCount: true
      reasonable: true
      supportMethodsArguments: true
      params: count=countSql;pageNum=pageNum;pageSize=pageSize;

3.1.3 Set the paging configuration in yml to the corresponding Bean

The @ConfigurationProperties annotation is used here to automatically fill the data with the specified prefix in the yml configuration file into the Bean.

(1) Paging attribute Bean of db1 data source

@Data
@Component
@ConfigurationProperties(prefix = "spring.pagehelper.db1")
public class PrimaryMybatisProperties {
    private String dialect;
    private String offsetAsPageNum;
    private String rowBoundsWithCount;
    private String reasonable;
    private String supportMethodsArguments;
    private String params;
}

(2) Paging attribute Bean of db2 data source

@Data
@Component
@ConfigurationProperties(prefix = "spring.pagehelper.db2")
public class SecondMybatisProperties {
    private String dialect;
    private String offsetAsPageNum;
    private String rowBoundsWithCount;
    private String reasonable;
    private String supportMethodsArguments;
    private String params;
}

3.1.4 Data source configuration

(1) Data source configuration of db1 PrimaryDataSourceConfig.java

Note: In the case of multiple data sources, the @Primary annotation is used here to specify that db1 is used by default.

@Configuration
@MapperScan(basePackages = "com.wen.mapper1", sqlSessionFactoryRef = "sqlSessionFactory1")
public class PrimaryDataSourceConfig {
    @Resource
    private PrimaryMybatisProperties primaryMybatisProperties;

    @Bean(name = "dataSource1")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.db1")
    public DataSource dataSource1(){
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "sqlSessionFactory1")
    @Primary
    public SqlSessionFactory sqlSessionFactory1(@Qualifier("dataSource1") DataSource dataSource1) throws Exception{
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource1);
        String locationPattern = "classpath*:mapper1/**/*.xml";
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sessionFactoryBean.setMapperLocations(resolver.getResources(locationPattern));
        // mybatis
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setLogImpl(StdOutImpl.class);
        sessionFactoryBean.setConfiguration(configuration);
        // paging
        Interceptor interceptor = new PageInterceptor();
        Properties properties = new Properties();
        properties.setProperty("helperDialect", primaryMybatisProperties.getDialect());
        properties.setProperty("offsetAsPageNum", primaryMybatisProperties.getOffsetAsPageNum());
        properties.setProperty("rowBoundsWithCount", primaryMybatisProperties.getRowBoundsWithCount());
        properties.setProperty("reasonable", primaryMybatisProperties.getReasonable());
        properties.setProperty("supportMethodsArguments",primaryMybatisProperties.getSupportMethodsArguments());
        properties.setProperty("params",primaryMybatisProperties.getParams());
        interceptor.setProperties(properties);
        sessionFactoryBean.setPlugins(interceptor);
        return sessionFactoryBean.getObject();
    }
    @Bean(name = "sqlSessionTemplate1")
    @Primary
    public SqlSessionTemplate sqlSessionTemplate1(@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory1) {
        return new SqlSessionTemplate(sqlSessionFactory1);
    }

    @Bean(name = "dataSourceTransactionManager1")
    @Primary
    public DataSourceTransactionManager dataSourceTransactionManager1(@Qualifier("dataSource1") DataSource dataSource1){
        return new DataSourceTransactionManager(dataSource1);

    }
}

(2) db2 data source configuration SecondDataSourceConfig.java

@Configuration
@MapperScan(basePackages = "com.wen.mapper2",sqlSessionFactoryRef = "sqlSessionFactory2")
public class SecondDataSourceConfig {
    @Resource
    private SecondMybatisProperties secondMybatisProperties;

    @Bean(name = "dataSource2")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.db2")
    public DataSource dataSource2(){
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "sqlSessionFactory2")
    @Primary
    public SqlSessionFactory sqlSessionFactory1(@Qualifier("dataSource2") DataSource dataSource2) throws Exception{
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource2);
        String locationPattern = "classpath*:mapper2/**/*.xml";
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sessionFactoryBean.setMapperLocations(resolver.getResources(locationPattern));
        // mybatis underline to camel case
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setLogImpl(StdOutImpl.class);
        sessionFactoryBean.setConfiguration(configuration);
        //Paging configuration
        Interceptor interceptor = new PageInterceptor();
        Properties properties = new Properties();
        properties.setProperty("helperDialect", secondMybatisProperties.getDialect());
        properties.setProperty("offsetAsPageNum", secondMybatisProperties.getOffsetAsPageNum());
        properties.setProperty("rowBoundsWithCount", secondMybatisProperties.getRowBoundsWithCount());
        properties.setProperty("reasonable", secondMybatisProperties.getReasonable());
        properties.setProperty("supportMethodsArguments",secondMybatisProperties.getSupportMethodsArguments());
        properties.setProperty("params",secondMybatisProperties.getParams());
        interceptor.setProperties(properties);
        sessionFactoryBean.setPlugins(interceptor);
        return sessionFactoryBean.getObject();
    }
    @Bean(name = "sqlSessionTemplate2")
    @Primary
    public SqlSessionTemplate sqlSessionTemplate1(@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory2) {
        return new SqlSessionTemplate(sqlSessionFactory2);
    }

    @Bean(name = "dataSourceTransactionManager2")
    @Primary
    public DataSourceTransactionManager dataSourceTransactionManager1(@Qualifier("dataSource2") DataSource dataSource2){
        return new DataSourceTransactionManager(dataSource2);

    }
}

Note: If the @Transactional transaction annotation is used in the project, the transaction management of the data source must be configured separately, which has been configured in the above code.

3.1.5 Startup class exclusion related automatic configuration

The startup class excludes the automatic configuration of data source (DataSourceAutoConfiguration.class), Mybatis (MybatisAutoConfiguration.class), and paging (PageHelperAutoConfiguration.class).

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, MybatisAutoConfiguration.class, PageHelperAutoConfiguration.class})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

3.2 Sample code

3.2.1 po

src/main/java/com/wen/po

@Data
public class Student {
    privateInteger id;
    private String name;
    private Integer age;
    private String gender;
    private String address;
    private Date birth;
}
@Data
public class User {
    private String id;
    private String userName;
}

3.2.2 controller layer

src/main/java/com/wen/controller

@RestController
@RequestMapping("/student")
public class StudentController {
    @Resource
    private StudentServiceI studentService;

    @GetMapping
    public PageInfo<Student> queryByPage(int pageNum, int pageSize, Student student){
        return studentService.queryByPage(pageNum,pageSize,student);
    }
}
@RestController
@RequestMapping("/user")
public class UserController {
    @Resource
    private UserServiceI userService;

    @GetMapping
    public PageInfo<User> queryByPage(int pageNum, int pageSize, User user){
        return userService.queryByPage(pageNum,pageSize,user);
    }
}

3.2.3 service layer

src/main/java/com/wen/service

public interface StudentServiceI {
    PageInfo<Student> queryByPage(int pageNum, int pageSize, Student student);

}
@Service
public class StudentServiceImpl implements StudentServiceI {
    @Resource
    private StudentMapper studentMapper;
    @Override
    public PageInfo<Student> queryByPage(int pageNum, int pageSize, Student student) {
        if (pageNum <= 0) {
            pageNum = 1;
        }
        if (pageSize <= 0) {
            pageSize = 10;
        }
        if(ObjectUtil.isEmpty(student)){
            student = new Student();
        }
        PageMethod.startPage(pageNum,pageSize);
        List<Student> students = studentMapper.selectByPage(student);
        PageInfo<Student> pageInfo = new PageInfo<>(students);
        return pageInfo;
    }
}
public interface UserServiceI {
    PageInfo<User> queryByPage(int pageNum, int pageSize, User user);
}
@Service
public class UserServiceImpl implements UserServiceI {
    @Resource
    private UserMapper userMapper;
    @Override
    public PageInfo<User> queryByPage(int pageNum, int pageSize, User user) {
        if (pageNum <= 0) {
            pageNum = 1;
        }
        if (pageSize <= 0) {
            pageSize = 10;
        }
        if(ObjectUtil.isEmpty(user)){
            user = new User();
        }
        PageMethod.startPage(pageNum,pageSize);
        List<User> users = userMapper.selectByPage(user);
        PageInfo<User> pageInfo = new PageInfo<>(users);
        return pageInfo;
    }
}

3.2.4 mapper layer

Pay attention to the mappers corresponding to different data sources. The attribute basePackages = “com.wen.mapper2” corresponding to @MapperScan in the data source configuration class specifies the mapper corresponding to the data source.

(1) Mapper layer corresponding to db1 data source

src/main/java/com/wen/mapper1/StudentMapper.java

@Mapper
public interface StudentMapper {
    List<Student> selectByPage(@Param("student") Student student);
}

src/main/resources/mapper1/StudentMapper.xml

<?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="com.wen.mapper1.StudentMapper">
    <sql id="student">
        id,name,age,gender,address,birth
    </sql>
    <select id="selectByPage" resultType="com.wen.po.Student">
        select
        <include refid="student"/>
        from student
        <where>
            <if test="student.id!=null">
                and id = #{student.id}
            </if>
            <if test="student.name!=null and student.name!=''">
                <bind name="stuName" value="'%' + student.name + '%'"/>
                and name like #{stuName}
            </if>
        </where>
    </select>
</mapper>

(2) Mapper layer corresponding to db2 data source

src/main/java/com/wen/mapper2/UserMapper.java

@Mapper
public interface UserMapper {
    List<User> selectByPage(@Param("user") User user);
}

src/main/resources/mapper2/UserMapper.xml

<?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="com.wen.mapper2.UserMapper">
    <sql id="user">
        id,user_name
    </sql>
    <select id="selectByPage" resultType="com.wen.po.User">
        select
        <include refid="user"/>
        from sys_user
        <where>
            <if test="user.id!=null">
                and id = #{student.id}
            </if>
            <if test="user.userName!=null and user.userName!=''">
                <bind name="userName" value="'%' + user.userName + '%'"/>
                and user_name like #{userName}
            </if>
        </where>
    </select>
</mapper>

3.3 Test

Use Postman to test as follows:

(1) Use db1 data source

(2) Use db2 data source

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 137733 people are learning the system