Build the simplest multi data source with mybatis plus as the framework (different data sources under different packages)



1.1 introducing pom dependency

 <!--introduce springboot Parent project dependency-->
    <!--Introduce dependency:
    It can be omitted version Tag to get some reasonable default configuration
    -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
    </parent>

    <!--Because use eureka,yes springCloud Yes, so it is introduced springCloud Version locking-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <!--spring cloud edition springBoott and springCloud The versions should correspond-->
        <spring-cloud.version>Hoxton.SR10</spring-cloud.version>
    </properties>
    <!--introduce Spring Cloud rely on-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!--introduce eureka-client jar Bag, this is eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!--Because you want to start this project, you need to start the class-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--use@Data reduce JavaBean get...set...method-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--link Spring Boot and MyBatis-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>


        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>



<!--Two for testing jar package-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>


    </dependencies>

1.2 application.yml configuration

  • It mainly configures multiple mysql addresses and eureka registration addresses
  • For eureka configuration, refer to: EurekaService server creation         EurekaClient client creation
  • Here is spring datasource. Master and spring datasource. The branch path is customized to read this data source from the code
server:
  #Client port number
  port: 8080


mybatis-plus:
  mapper-locations: classpath*:mappings/*/*.xml #Scan mapper
  type-aliases-package: com.it.mhh.entity #Scan entity class
  global-config:
    banner: false
    db-config:
      id-type: ID_WORKER #Primary key type NONE: "database ID self increment", INPUT: "user INPUT ID", ID_WORKER: "globally unique ID (unique ID of digital type)", UUID: "globally unique ID UUID", AUTO: MP determines automatically;
      logic-not-delete-value: normal #Logical delete configuration
      logic-delete-value: deleted #Logical delete configuration
  configuration:
    map-underscore-to-camel-case: true

spring:
  datasource:
    master:
      driver-class-name: com.mysql.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/mhh_master?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
      username: root
      password: root
    branch:
      driver-class-name: com.mysql.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/mhh_branch?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
      username: root
      password: root
  application:
    #Client registration name, the name of the Application in the registration center
    name: client-general-mapper

eureka:
  client:
    #Because it is a client, it needs to register itself and register in Eureka server. Default: true
    register-with-eureka: true
    #Pull a service from the client. Later, you use more than one service. You may call other services in the server through the feign interface, so you need to pull the service. Default: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka # registry address. If there is a cluster, write several, separated by commas
  instance:
    # Prefer ip addresses to host names
    prefer-ip-address: true
    #Name of test item Status in the registry
    instance-id: ${eureka.instance.ip-address}
    # ip address this is the registered address of the client. eureka will establish a pipeline through this address
    ip-address: 127.0.0.1  #Default 0.0.0.0.0.1
    # Indicates the frequency of heartbeat sent by eureka client to the server. The renewal interval is 30 seconds by default (as long as the server does not receive it, it will not be directly eliminated, and the Status will be changed to Down first)
    lease-renewal-interval-in-seconds: 5
    # Indicates the timeout time for eureka server to wait for the next heartbeat after receiving the client's heartbeat last time. If the next heartbeat is not received within this time, the instance will be removed
    lease-expiration-duration-in-seconds: 15


1.3 JavaBean objects

1.3.1 the first data source Master JavaBean object

  • mybatisplus annotations are used
  • @There are five in Data
  • This javaBean object corresponds to a table in MySql. Specify the table name with the @ TableName annotation
  • @TableField(fill = FieldFill. *) fill in this annotation is the filling policy of the fields of the specified database table
  • To implement the myBatisPlus auto fill policy, you need to implement the MetaObjectHandler interface in myBatisPlus
  • Here we mainly talk about the configuration of multiple data sources, not more about mybatisplus (specifically written in the later stage)
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@TableName("student")
public class StudentMaster implements Serializable {

    public StudentMaster(long masterId, String masterName, Integer masterAge) {
        this.masterId = masterId;
        this.masterName = masterName;
        this.masterAge = masterAge;
    }

    /*
         INPUT If the developer does not assign a value manually, the database assigns a value to the primary key by self increment. If the developer assigns a value manually, the value is stored.
         AUTO The default is database self increment, and developers do not need to assign values.
         ASSIGN_ID MP Automatic assignment, snowflake algorithm.
         ASSIGN_UUID The data type of the primary key must be String. UUID is automatically generated for assignment
       * */
    @TableId(value = "id",type = IdType.ASSIGN_ID)
    private long masterId;


    /*
        Mapping non primary key field, value mapping field name
        exist Indicates whether it is a database field false. If the member variable in the entity class does not have a corresponding field in the database, exist, VO and DTO can be used
        select Indicates whether to query the field
        fill Indicates whether to automatically fill in. When saving objects into the database, MyBatis Plus automatically assigns values to some fields, create_time,update_time
    * */
    @TableField(value = "name")
    private String masterName;

    @TableField(value = "age")
    private Integer masterAge;


    // Add fill for the first time
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createDate;

    // It is populated when it is added for the first time, but it will also be populated after each update
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateDate;

}


1.3.2 Branch JavaBean object of the second data source

  • mybatisplus annotations are used
  • This javaBean object corresponds to a table in MySql. Specify the table name with the @ TableName annotation
  • @TableField(fill = FieldFill. *) fill in this annotation is the filling policy of the fields of the specified database table
  • To implement the myBatisPlus auto fill policy, you need to implement the MetaObjectHandler interface in myBatisPlus
  • Here we mainly talk about the configuration of multiple data sources, not more about mybatisplus (specifically written in the later stage)
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.util.Date;

@Data
@TableName("student")
public class StudentBranch {
    public StudentBranch(long branchId, String branchName, String branchAddress, String branchTeacher) {
        this.branchId = branchId;
        this.branchName = branchName;
        this.branchAddress = branchAddress;
        this.branchTeacher = branchTeacher;
    }

    /*
         INPUT If the developer does not assign a value manually, the database assigns a value to the primary key by self increment. If the developer assigns a value manually, the value is stored.
         AUTO The default is database self increment, and developers do not need to assign values.
         ASSIGN_ID MP Automatic assignment, snowflake algorithm.
         ASSIGN_UUID The data type of the primary key must be String. UUID is automatically generated for assignment
       * */
    @TableId(value = "id",type = IdType.ASSIGN_ID)
    private long branchId;


    /*
        Mapping non primary key field, value mapping field name
        exist Indicates whether it is a database field false. If the member variable in the entity class does not have a corresponding field in the database, exist, VO and DTO can be used
        select Indicates whether to query the field
        fill Indicates whether to automatically fill in. When saving objects into the database, MyBatis Plus automatically assigns values to some fields, create_time,update_time
    * */
    @TableField(value = "name")
    private String branchName;

    @TableField(value = "address")
    private String branchAddress;

    @TableField(value = "teacher")
    private String branchTeacher;

    // Add fill for the first time
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    // It is populated when it is added for the first time, but it will also be populated after each update
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

}



1.4 myBatisPlus auto fill strategy

  • This is mainly combined with the fill attribute in @ TableField() in JavaBean object
  • @The fill attribute in TableField() is fieldfill Insert means that the value is assigned only when adding for the first time, and the insertFill method of the processing class will be filled automatically
  • @The fill attribute in TableField() is fieldfill INSERT_ Update means that the value will be assigned automatically when adding or modifying. Follow the updateFill method of the self filling processing class below
  • The MetaObjectHandler interface is required to implement the auto fill policy
  • Setfieldvalbyname (string fieldname, object fieldval, metaobject, metaobject) three input parameters. The first is to assign a value to which attribute, fill in the attribute name, the second is to automatically fill in the value, and the third is a meta object
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Date;

/**
 * Auto fill processing class
 * @author Mhh
 * @version 1.0
 * @see
 **/
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
  private static final Logger logger = LoggerFactory.getLogger(MyMetaObjectHandler.class);


  public MyMetaObjectHandler() {
  }


  public void insertFill(MetaObject metaObject) {
    this.setFieldValByName("createDate", LocalDateTime.now(), metaObject);
    this.setFieldValByName("createTime", new Date(), metaObject);
    this.setFieldValByName("updateDate", LocalDateTime.now(), metaObject);
    this.setFieldValByName("updateTime", new Date(), metaObject);
  }

  public void updateFill(MetaObject metaObject) {
    this.setFieldValByName("updateDate", LocalDateTime.now(), metaObject);
    this.setFieldValByName("updateTime", new Date(), metaObject);
  }
}

1.5 data source configuration


1.5.1 Master data source configuration

  • A big hole: I use mybatisplus. Mybatisplus has its own data source MybatisSqlSessionFactoryBean. Using SqlSessionFactoryBean will report Invalid bound statement not found * * error
  • Hump naming: mybatisconfiguration setMapUnderscoreToCamelCase(true); Because the DataSource is written by yourself now, all yml configured data sources no longer work
  • Import auto fill class: note that the user-defined auto fill class just written is imported. Because it is a handwritten DataSource, java will not import it manually. Otherwise, it will not take effect
  • Configure mapper's xml format file: the location of mapper's xml format file must be configured, otherwise an error will be reported: no statement, because it is your own handwriting DataSource now, and all yml configurations are no longer functional
  • @Attribute configuration in MapperScan annotation: basePackages attribute: the core I need to specify which package to scan, then all mappers under this package will go through this configuration. sqlSessionFactoryRef attribute: since we know which mappers under those packages go through those configurations, this attribute is the specified data source, and @ Bean has specified the name of the data source
  • @Primary: indicates that this data source is the default data source. This annotation must be added, because if it is not added, spring will not be able to distinguish the primary data source (default data source)
  • @ConfigurationProperties note: the prefix property in specifies the address, account and password of MySql configured in yml
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.it.mhh.utils.MyMetaObjectHandler;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = "com.it.mhh.master.dao", sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {

    @Autowired
    private MyMetaObjectHandler myMetaObjectHandler;

    @Primary // Indicates that this data source is the default data source, and this annotation must be added, because if it is not added, spring will not be able to distinguish the primary data source (the default data source)
    @Bean("masterDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.master") //Read application The configuration parameters in YML are mapped into an object
    public DataSource getmasterDataSource(){
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean("masterSqlSessionFactory")
    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {
        //SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        //Hump naming
        //org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
        mybatisConfiguration.setMapUnderscoreToCamelCase(true);
        //Introduce custom to automatically populate classes
        GlobalConfig globalConfig=new GlobalConfig();
        globalConfig.setMetaObjectHandler(myMetaObjectHandler);
        bean.setGlobalConfig(globalConfig);
        //configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(mybatisConfiguration);

        // The location of the mapper's xml file must be configured, or an error will be reported: no statement (this error may also be caused by the inconsistency between the namespace and the project path in the mapper's xml)
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mappings/master/*.xml"));
        return bean.getObject();
    }

    @Primary
    @Bean("masterSqlSessionTemplate")
    public SqlSessionTemplate masterSqlSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}


1.5.1 branch data source configuration

  • A big hole: I use mybatisplus. Mybatisplus has its own data source MybatisSqlSessionFactoryBean. Using SqlSessionFactoryBean will report Invalid bound statement not found * * error
  • Hump naming: mybatisconfiguration setMapUnderscoreToCamelCase(true); Because the DataSource is written by yourself now, all yml configured data sources no longer work
  • Import auto fill class: note that the user-defined auto fill class just written is imported. Because it is a handwritten DataSource, java will not import it manually. Otherwise, it will not take effect
  • Configure mapper's xml format file: the location of mapper's xml format file must be configured, otherwise an error will be reported: no statement, because it is your own handwriting DataSource now, and all yml configurations are no longer functional
  • @Attribute configuration in MapperScan annotation: basePackages attribute: the core I need to specify which package to scan, then all mappers under this package will go through this configuration. sqlSessionFactoryRef attribute: since we know which mappers under those packages go through those configurations, this attribute is the specified data source, and @ Bean has specified the name of the data source
  • @Primary: indicates that this data source is the default data source. This annotation must be added, because if it is not added, spring will not be able to distinguish the primary data source (default data source)
  • @ConfigurationProperties note: the prefix property in specifies the address, account and password of MySql configured in yml
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.it.mhh.utils.MyMetaObjectHandler;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = "com.it.mhh.branch.dao", sqlSessionFactoryRef = "branchSqlSessionFactory")
public class BranchDataSourceConfig {

    @Autowired
    private MyMetaObjectHandler myMetaObjectHandler;

    @Bean("branchDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.branch")
    public DataSource getBranchDataSource(){
        return DataSourceBuilder.create().build();
    }

    @Bean("branchSqlSessionFactory")
    public SqlSessionFactory branchSqlSessionFactory(@Qualifier("branchDataSource") DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        //Hump naming
        //org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
        mybatisConfiguration.setMapUnderscoreToCamelCase(true);
        //configuration.setMapUnderscoreToCamelCase(true);
        //Introduce custom to automatically populate classes
        GlobalConfig globalConfig=new GlobalConfig();
        globalConfig.setMetaObjectHandler(myMetaObjectHandler);
        bean.setGlobalConfig(globalConfig);
        bean.setConfiguration(mybatisConfiguration);

        // The location of the mapper's xml file must be configured, or an error will be reported: no statement (this error may also be caused by the inconsistency between the namespace and the project path in the mapper's xml)
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mappings/branch/*.xml"));
        return bean.getObject();
    }

    @Bean("branchSqlSessionTemplate")
    public SqlSessionTemplate branchSqlSessionTemplate(@Qualifier("branchSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

1.6 snowflake algorithm tools

snowFlake.nextId(): get value, Long type

public class SnowFlake {
    // Starting timestamp
    private final static long START_STMP = 1577808000000L; //2020-01-01
    // The number of bits occupied by each part is three
    private final static long SEQUENCE_BIT = 12; //Number of digits occupied by serial number
    private final static long MACHINE_BIT = 5; //Number of digits occupied by machine identification
    private final static long DATACENTER_BIT = 5; //Number of bits occupied by data center
    // Maximum value of each part
    private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
    // Displacement of each part to the left
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
    private long datacenterId; //Data center
    private long machineId; //Machine identification
    private long sequence = 0L; //serial number
    private long lastStmp = -1L; //Last timestamp

    public SnowFlake(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    //Generate next ID
    public synchronized long nextId() {
        long currStmp = timeGen();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currStmp == lastStmp) {
            //The if condition indicates that the current call and the last call fall in the same milliseconds, and can only be judged by the third part, and the serial number is added from the same time, so +1.
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //The number of sequences in the same millisecond has reached the maximum. You can only wait for the next millisecond
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            //Within different milliseconds, the serial number is set to 0
            //The premise of executing this branch is currtimestamp > lasttimestamp, which means that compared with the last call, this call is no longer within the same millisecond, and the serial number can be reset to 0 at this time.
            sequence = 0L;
        }

        lastStmp = currStmp;
        //It is spliced with relative milliseconds, machine ID and self incrementing sequence number
        return (currStmp - START_STMP) << TIMESTMP_LEFT //Timestamp part
                | datacenterId << DATACENTER_LEFT       //Data center part
                | machineId << MACHINE_LEFT             //Machine identification part
                | sequence;                             //Serial number part
    }

    private long getNextMill() {
        long mill = timeGen();
        while (mill <= lastStmp) {
            mill = timeGen();
        }
        return mill;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

}

1.7 xml configuration

Note that it must correspond to the xml file location of the mapper of the handwritten data source

MasterDaoMapper

<?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.it.mhh.master.dao.MasterDaoMapper">

</mapper>

BranchDaoMapper

<?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.it.mhh.branch.dao.BranchDaoMapper">

</mapper>

1.8 startup class configuration

  • The snowflake algorithm tool class is introduced into ioc
  • Two values of the snowflake algorithm input parameter: machine Id, as long as it does not duplicate other machine IDS (range: 0-32, 0-32)
import com.it.mhh.utils.SnowFlake;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;

@EnableEurekaClient
@SpringBootApplication
public class MultipleDataSourcesApplication {

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

    @Bean
    public SnowFlake snowFlake(){
        return new SnowFlake(0,0);
    }
}

1.9 data source test


1.9.1 Master data source test

Controller layer: MasterController

import com.it.mhh.entity.StudentMaster;
import com.it.mhh.master.service.MasterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("master")
public class MasterController {

    @Autowired
    private MasterService masterService;


    @RequestMapping("/insertMaster")
    public Boolean insertMaster(@RequestBody StudentMaster studentMaster) {

        return masterService.insertMaster(studentMaster);
    }

    public Boolean updateMaster(@RequestBody StudentMaster studentMaster) {

        return masterService.updateMaster(studentMaster);
    }
}

ServiceImpl layer: MasterServiceImpl

Mybatis plus's general Service: the implementation class inherits serviceimpl < < Mapper interface of operating entity, specific entity class >, and finally adds the annotation @ Service to take this class as a Bean under the Spring container.

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.it.mhh.entity.StudentMaster;
import com.it.mhh.master.dao.MasterDaoMapper;
import com.it.mhh.master.service.MasterService;
import org.springframework.stereotype.Service;

@Service
public class MasterServiceImpl extends ServiceImpl<MasterDaoMapper, StudentMaster> implements MasterService {


    @Override
    public Boolean insertMaster(StudentMaster studentMaster) {
        return this.baseMapper.insert(studentMaster)>0?true:false;
    }
    
    @Override
    public Boolean updateMaster(StudentMaster studentMaster) {
        return this.baseMapper.updateById(studentMaster)>0?true:false;

    }
}


dao layer: MasterDaoMapper

  • Under which package: Here I intercepted the package path, corresponding to the basePackages attribute in the @ MapperScan annotation of the handwritten data source
package com.it.mhh.master.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.it.mhh.entity.StudentMaster;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface MasterDaoMapper extends BaseMapper<StudentMaster> {
    
}


Test:

  • You can see that the date is also added. I didn't assign a value to the date, indicating that the above myBatisPlus automatic filling policy takes effect
  • Through @ MapperScan annotation scanning, it can be seen that the configuration of masterSqlSessionFactory is followed; The MySql address and table configured by masterSqlSessionFactory are localhost:3306/mhh_master
  • Test mode test results:
import com.it.mhh.entity.StudentMaster;
import com.it.mhh.master.controller.MasterController;
import com.it.mhh.utils.SnowFlake;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
public class MultipleDataSourcesApplicationTest {

    @Autowired
    private MasterController masterController; //Master data source
    

    @Autowired
    private SnowFlake snowFlake; //Snowflake algorithm

    @Test
    public void masterInsert() {
        Boolean aBoolean = masterController.insertMaster(new StudentMaster(snowFlake.nextId(), "Xiaobai", 12));
        System.out.println(aBoolean);
    }
}


1.9.2 Branch data source test

Controller layer: MasterController

import com.it.mhh.branch.service.BranchService;
import com.it.mhh.entity.StudentBranch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("branch")
public class BranchController {
    @Autowired
    private BranchService branchService;

    @RequestMapping(value = "insertBranch")
    public Boolean insertBranch(@RequestBody StudentBranch studentBranch) {
        return  branchService.insertBranch(studentBranch);
    }
}

ServiceImpl layer: MasterServiceImpl

Mybatis plus's general Service: the implementation class inherits serviceimpl < < Mapper interface of operating entity, specific entity class >, and finally adds the annotation @ Service to take this class as a Bean under the Spring container.

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.it.mhh.branch.dao.BranchDaoMapper;
import com.it.mhh.branch.service.BranchService;
import com.it.mhh.entity.StudentBranch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BranchServiceImpl extends ServiceImpl<BranchDaoMapper, StudentBranch> implements BranchService {

 /*   @Autowired
    private BranchDaoMapper branchDaoMapper;*/

    public Boolean insertBranch(StudentBranch studentBranch) {
        return this.baseMapper.insert(studentBranch)>0?true:false;
    }
}



dao layer: MasterDaoMapper

  • Under which package: Here I intercepted the package path, corresponding to the basePackages attribute in the @ MapperScan annotation of the handwritten data source
package com.it.mhh.branch.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.it.mhh.entity.StudentBranch;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface BranchDaoMapper extends BaseMapper<StudentBranch> {
}


Test:

  • You can see that the date is also added. I didn't assign a value to the date, indicating that the above myBatisPlus automatic filling policy takes effect
  • Through @ MapperScan annotation scanning, it can be seen that the configuration of masterSqlSessionFactory is followed; The MySql address and table configured by masterSqlSessionFactory are localhost:3306/mhh_branch
  • Test mode test results:
import com.it.mhh.branch.controller.BranchController;
import com.it.mhh.entity.StudentBranch;
import com.it.mhh.utils.SnowFlake;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
public class MultipleDataSourcesApplicationTest {
    
    @Autowired
    private BranchController branchController; //Branch data source
    
    @Autowired
    private SnowFlake snowFlake; //Snowflake algorithm
  
    
    @Test
    public void branchInsaert(){
        Boolean aBoolean = branchController.insertBranch(new StudentBranch(snowFlake.nextId(), "Xiao Hei", "Shandong","Blue "));
        System.out.println(aBoolean);//true
    }
}







Link: Take mybatis plus as the framework to build the simplest multiple data sources (different data sources under different packages) as an example, and use the source code download address

Keywords: Java JDBC Mybatis Spring Boot

Added by fred_m on Mon, 17 Jan 2022 02:18:53 +0200