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>

相关文章
相关标签/搜索