spring boot (mybatis 實現多數據源 輪詢配置)

 

實現原理:java

關鍵點一 (去掉spring boot 默認的mybatis 自動配置)mysql

spring boot 集成 mybatis 內部默配置只能使用 單實例的數據源。可是在實現多數據源時。不能使用 默認的配置,首先要去掉spring boot 默認的mybatis 自動配置:web

 

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)spring

public class MybatisApplication {sql

         public static void main(String[] args) {數據庫

                   SpringApplication.run(MybatisApplication.class, args);服務器

         }mybatis

}app

關鍵點二 (使用動態數據源)ide

若是咱們要實現多數據庫讀寫分離,就須要查詢或修改的數據的時候,調用對應的數據庫,spring boot jdbc 提供了一個 AbstractRoutingDataSource,經過實現,咱們能夠在操做數據庫以前,動態的設置 數據源:

 

public class DynamicDataSource extends AbstractRoutingDataSource{

    @Override

    protected Object determineCurrentLookupKey() {

        String dataSourceType = DatabaseContextHolder.getDataSourceType();

        System.out.println("動態獲取到的 數據源key == "+dataSourceType);

        return dataSourceType;

    }

}

關鍵點三 (使用 ThreadLoacl 實現信息傳遞)

DatabaseContextHolder 內部使用 ThreadLocal 類,經過ThreadLocal 能夠給每一個線程設置和獲取數據,起做用是在 AOP攔截到對應的 方法時,實現讀寫分離。

 

public class DatabaseContextHolder {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal();

    public static void setDataSourceType(String dataSourceType) {

        contextHolder.set(dataSourceType);

    }

    public static String getDataSourceType() {

        return contextHolder.get();

    }

}

關鍵點四(配置多數據源)

多數據源 使用默認的 properties配置確定是不行的了,這裏就須要咱們使用 自定義的配置。

在 resouce 目錄下建立一個 multidatabase.properties 文件,內容以下。

 

#下面的main  和 read 數據將會以輪詢的方式 被 訪問。

#mian 循環main

#read 循環read  具體代碼查看DataSourceAOP

 

#自定義多數據源配置

my.datasource.driver=com.mysql.jdbc.Driver

 

#  main 表明主服務器 可讀寫   read  = 只讀

my.datasource[0].type=main

my.datasource[0].url=jdbc:mysql://rm-bp1jxj7m4egc7ce118o.mysql.rds.aliyuncs.com:3306/zllshop

my.datasource[0].username=lichuan

my.datasource[0].password=2018515

 

my.datasource[1].type=read

my.datasource[1].url=jdbc:mysql://rm-bp1jxj7m4egc7ce118o.mysql.rds.aliyuncs.com:3306/zllshop1

my.datasource[1].username=lichuan

my.datasource[1].password=2018515

 

my.datasource[2].type=read

my.datasource[2].url=jdbc:mysql://rm-bp1jxj7m4egc7ce118o.mysql.rds.aliyuncs.com:3306/zllshop

my.datasource[2].username=lichuan

my.datasource[2].password=2018515

 

my.datasource[3].type=main

my.datasource[3].url=jdbc:mysql://rm-bp1jxj7m4egc7ce118o.mysql.rds.aliyuncs.com:3306/zllshop1

my.datasource[3].username=lichuan

my.datasource[3].password=2018515

關鍵點五(讀取配置文件)

@Configuration

@MapperScan(basePackages = "com.example.mybatis.mapper")

@PropertySource(value = "classpath:multidatabase.properties", encoding = "utf-8")

@ConfigurationProperties("my")

@Data

public class MultDataSource {

    public static final String MAIN = "main";

    public static final String READ = "read";

 

    public List<String> mainKeys = new ArrayList<>();

    public List<String> readKeys = new ArrayList<>();

 

    @Value("${my.datasource.driver}")

    private String driver;

 

    /**

     *  讀取配置文件獲取。

     */

    private List<MyDatabase> datasource;

 

    public DruidDataSource getDataSource(MyDatabase database) {

        DruidDataSource druidDataSource = new DruidDataSource();

        druidDataSource.setUrl(database.getUrl());

        druidDataSource.setUsername(database.getUsername());

        druidDataSource.setDriverClassName(driver);

        druidDataSource.setPassword(database.getPassword());

        druidDataSource.setInitialSize(1);

        druidDataSource.setMaxWait(6000);

        druidDataSource.setMinIdle(8);

        return druidDataSource;

    }

 

    @Bean

    @Primary

    public DynamicDataSource dataSource() {

        Map<Object, Object> targetDataSources = new HashMap<>();

        for (int i = 0; i < datasource.size(); i++) {

            String type = datasource.get(i).getType();

            DruidDataSource dataSource = getDataSource(datasource.get(i));

            if (MAIN.equals(type)) {

                mainKeys.add(MAIN+i);

                targetDataSources.put(MAIN+i,dataSource);

            } else {

                readKeys.add(READ+i);

                targetDataSources.put(READ+i,dataSource);

            }

        }

        DynamicDataSource dataSource = new DynamicDataSource();

        // 該方法是AbstractRoutingDataSource的方法

        dataSource.setTargetDataSources(targetDataSources);

        // 默認的datasource設置爲myTestDbDataSource

        dataSource.setDefaultTargetDataSource(targetDataSources.get(mainKeys.get(0)));

        return dataSource;

    }

}

關鍵點六(AOP 攔截代碼)

UserMapper 類 這裏沒有貼出 mapper.xml

 

package com.example.mybatis.mapper;

@Component

@Mapper

public interface UserMapper {

    int deleteByPrimaryKey(Long id);

    int insert(User record);

    User selectByPrimaryKey(Long id);

    List<User> selectAll();

    int updateByPrimaryKey(User record);

}

AOP 攔截類

 

@Aspect

@Component

public class DataSourceAop {

 

    @Autowired

    MultDataSource multDataSource;

 

 

    @Before("execution(* com.example.mybatis.mapper..*.get*(..)) || " +

            "execution(* com.example.mybatis.mapper..*.list*(..)) ||"+

            "execution(* com.example.mybatis.mapper..*.select*(..))")

    public  void setReadDataSource(){

        DatabaseContextHolder.setDataSourceType(getReadKey());

        System.out.println("我是讀");

    }

 

    @Before("execution(* com.example.mybatis.mapper..*.add*(..)) || " +

            "execution(* com.example.mybatis.mapper..*.update*(..)) ||"+

            "execution(* com.example.mybatis.mapper..*.insert*(..)) ||"+

            "execution(* com.example.mybatis.mapper..*.delete*(..))")

    public  void setWriteDataSource(){

        DatabaseContextHolder.setDataSourceType(getMainKey());

        System.out.println("我是寫");

    }

 

    /**

     * 輪詢方式

     */

    int m = 0;

    public String getMainKey(){

        List<String> readKeys = multDataSource.getMainKeys();

        m ++;

        m = m%readKeys.size();

        return readKeys.get( m );

    }

 

    int i = 0;

    public String getReadKey(){

        List<String> readKeys = multDataSource.getReadKeys();

        i ++;

        i = i%readKeys.size();

       return readKeys.get( i );

    }

}

須要的依賴:

 

    <dependencies>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

        <dependency>

            <groupId>org.mybatis.spring.boot</groupId>

            <artifactId>mybatis-spring-boot-starter</artifactId>

            <version>2.0.0</version>

        </dependency>

 

        <dependency>

            <groupId>mysql</groupId>

            <artifactId>mysql-connector-java</artifactId>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>org.projectlombok</groupId>

            <artifactId>lombok</artifactId>

            <optional>true</optional>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-test</artifactId>

            <scope>test</scope>

        </dependency>

 

        <dependency>

            <groupId>com.alibaba</groupId>

            <artifactId>druid</artifactId>

            <version>1.1.7</version>

        </dependency>

 

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-aop</artifactId>

        </dependency>

 

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-configuration-processor</artifactId>

            <optional>true</optional>

        </dependency>

    </dependencies>

相關文章
相關標籤/搜索