Spring Boot Series: Seven achieve Mybatis switch multiple data sources

First, the configuration related to the introduction maven

mybatis; mysql drive; JDBC

         <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.18</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>

Second, write a configuration file

Configuring two data sources: here I configured a Tencent cloud database and a local database

Specify four fields: the database link, user name, password, driver

 

 Third, write database type enumeration

 

public enum DataSourceEnum {

    TENCENT(0),LOCAL(1);

    private  int value;

    private DataSourceEnum(int _value)
    {
        this.value=_value;
    }
}

Fourth, write a configuration file to read helper

Note: I made this step here is to show more transparency in the process of configuring a data source, if you want to be lazy, this step can not do it, read the configuration files directly injected into the container through annotations

DataSourceElement database link entity
/ * Database link entity class 
* fields and profiles consistent * / 
public  class DataSourceElement { 

    Private   String url; 

    Private String userName; 

    Private String password; 

   Private String classDirver; 
// ignore setter getter }
DataSourceItem class configuration read Help
@Component 
@ConfigurationProperties (prefix = "spring.datasource" )
 public  class DataSourceItem {
     // Tencent cloud configuration file corresponding to the link-DB Tencent 
    Private   DataSourceElement tencentDb;
    // local configuration file corresponding to the link-DB local 
    Private DataSourceElement LocalDB; 
   // Ignore getter serrer 
}

Fifth, get help writing class data sources in the current thread of execution

This class is required to specify the data sources used in our current thread

public  class DynamicDataSourceManger { 

    / * 
    * Initialize the current thread database type * / 
    Private  static  Final the ThreadLocal <DataSourceEnum> = threadLocalDbType new new the ThreadLocal <DataSourceEnum> () { 
        @Override 
        protected DataSourceEnum the initialValue () {
             return DataSourceEnum.TENCENT; 
        } 

        ; 
    }; 

    / * Get current thread database * / 
    public  static DataSourceEnum GET () {
         return threadLocalDbType.get (); 
    } 

    / * set the current thread database * / 
    public static  void SET (DataSourceEnum dataSourceEnum) { 
        threadLocalDbType.set (dataSourceEnum); 
    } 

    / * clear the current thread database cache * / 
    public  static  void RESET () { 
        threadLocalDbType.remove (); 
    } 
}

 

Six, inherited AbstractRoutingDataSource

AbstractRoutingDataSource is dynamically switch data sources to provide tools like spring, he can realize the data source routing switch during operation, please also check the official document, just write to me how to use 
simple terms that he would come get us through our designated key set of different data sources, data source arranged below will be written.

Here the data source to get the current thread to be executed by DynamicDataSourceManger we write the above key
public  class DynamicDataSource the extends AbstractRoutingDataSource { 
    @Override 
    protected Object determineCurrentLookupKey () {
         / * reads the current thread data source configured key value * / 
        return DynamicDataSourceManger.get (); 
    } 
}

Seven configure multiple data sources, and to achieve the AbstractRoutingDataSource

Note: The following code I used to write in our fourth class profiles help to get the contents of the configuration file to achieve the Bean injection, doing so for the convenience of the reader to understand the process of creating a DataSource

You may be directly used @ConfigurationProperties (prefix = "spring.datasource.tencent-db") directly mounted up, so only need to write one line

. DataSource dataSource = DataSourceBuilder.create () build (); to

note: 1 We need to specify unreasonable barrier for the data source Bean name to prevent conflicts.
2. The need to add @Primary on the acquisition Bean AbstractRoutingDataSource realized
3. after preparation of the spring need to turn off automatically configure the data source, otherwise it will lead to cyclic dependencies (write below)

the spring vessel injection category
/ * Data source implant * / 
@Configuration 
public  class DynamicDataSourceConfiguration { 

    / * get the database link * / 
    @Autowired 
    DataSourceItem dataSourceItem; 

    / * injection Tencent cloud database * / 
    @Bean (name = "TENCENTDB" )
     public the DataSource getTencentDataSource () { 
        DataSourceElement tencentSoure = dataSourceItem.getTencentDb (); 
        the DataSource the dataSource = DataSourceBuilder.create () 
                .url (tencentSoure.getUrl ())  
                .username (tencentSoure.getUserName ())
                .password (tencentSoure.getPassword ())
                .driverClassName(tencentSoure.getClassDirver())
                .build();
        return dataSource;
    }

    /*注入本地数据库*/
    @Bean(name = "LOCALDB")
    public DataSource getLocalDataSource() {
        DataSourceElement localSource = dataSourceItem.getLocalDb();
        DataSource dataSource = DataSourceBuilder.create()
                .url(localSource.getUrl())
                .username(localSource.getUserName())
                .password(localSource.getPassword())
                .driverClassName(localSource.getClassDirver())
                .build();
        return dataSource;
    }

    /*注入AbstractRoutingDataSource*/
    @Bean
    @Primary
    public DynamicDataSource getDyanmiceDataSource(@Qualifier("TENCENTDB") DataSource tencentDb,
                                                   @Qualifier("LOCALDB") DataSource localDb) {

        Map<Object,Object> hashMap=new HashMap<Object, Object>();
        hashMap.put(DataSourceEnum.TENCENT,tencentDb);
        hashMap.put(DataSourceEnum.LOCAL,localDb);

        DynamicDataSource dataSource= New new DynamicDataSource ();
         / * set the data source * / 
        dataSource.setTargetDataSources (hashMap '); 
        / * set the default data source * / 
        dataSource.setDefaultTargetDataSource (tencentDb); 
        / * invoke methods implement data source configuration * / 
        dataSource.afterPropertiesSet () ; 
        return the dataSource; 
    } 

}
Spring Boot startup settings change, the data source automatically shut down and manual injection configuration class our injected into the vessel IOC
@Import(DynamicDataSourceConfiguration.class)
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DynamicApplication {

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

}

Eight, write entity classes, Mybatis the Mapper and XML, configuration Mybatis

Here I built a table called t_user in Tencent cloud, built in the local library table called a person of

We are writing their Mapper and entities, and XML.

The following codes are removed from the get and set, and the code is written together to facilitate comparison, the actual open time is written (which is the basis of it .... I should not say)

public class Person {

    private Integer id;

    private  String name;

    private String address;

    private String province;

    private  String city;

    private  String area;
}
public class User {

    private Integer id;

    private String name;

    private String sex;

    private String address;

    private String city;

    private String area;
}

Mapper

@Mapper
public interface PersonMapper {

    List<Person> selectAllPerson();
}

@Mapper
public interface UserMapper {

    List<User> selectAllUser();
}

XML

<mapper namespace="com.example.dynamic.mapper.PersonMapper">
    <select id="selectAllPerson" resultType="com.example.dynamic.model.Person">
        select * from person
    </select>
</mapper>

<mapper namespace="com.example.dynamic.mapper.UserMapper">
    <select id="selectAllUser" resultType="com.example.dynamic.model.User">
        select * from t_user
    </select>
</mapper>

interface

We both interfaces were called Tencent cloud and two local data sources, before calling in DynamicDataSourceManger written by switching fifth to implement key source of data for the current thread

@RestController
@RequestMapping("/hello")
public class DynamicDataSourceController {

    @Autowired
    UserMapper userMapper;

    @Autowired
    PersonMapper personMapper;

    @RequestMapping("/user")
    public List<User> selectAllUser(){
        DynamicDataSourceManger.set(DataSourceEnum.TENCENT);
        return  userMapper.selectAllUser();
    }

    @RequestMapping("/person")
    public List<Person> selectAllPerson(){
        DynamicDataSourceManger.set(DataSourceEnum.LOCAL);
        return  personMapper.selectAllPerson();
    }
}

Nine, call interface

Call Tencent cloud data source

 

 Call local data source

 

 We found that this time has been achieved to switch multiple data sources, such an approach is actually a little stiff, you need to manually set the data source, by way of AOP compiled into the data source settings

It would be more convenient, I would not bother to write here, I believe we will springAOP.

Guess you like

Origin www.cnblogs.com/Tassdar/p/12113306.html