0
点赞
收藏
分享

微信扫一扫

spring boot (mybatis 实现多数据源 轮询配置)

Sophia的玲珑阁 2022-04-06 阅读 69


源码地址:https://gitee.com/leonzhang2013/mybaits__multiple_data_sources

实现原理:

关键点一 (去掉spring boot 默认的mybatis 自动配置)

spring boot 集成 mybatis 内部默配置只能使用 单实例的数据源。但是在实现多数据源时。不能使用 默认的配置,首先要去掉spring boot 默认的mybatis 自动配置:


@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

public class MybatisApplication {

         public static void main(String[] args) {

                   SpringApplication.run(MybatisApplication.class, args);

         }

}

关键点二 (使用动态数据源)

如果我们要实现多数据库读写分离,就需要查询或修改的数据的时候,调用对应的数据库,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>


举报

相关推荐

0 条评论