Skip to content

Latest commit

 

History

History
192 lines (150 loc) · 6.1 KB

multi-datasource.md

File metadata and controls

192 lines (150 loc) · 6.1 KB

读写分离 & 多数据源

推荐使用 shardingjdbc 分布式数据库中间件,实现分库分表、读写分离。

dynamic-datasource-spring-boot-starter

官网地址 https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter

示例项目 https://gitee.com/baomidou/dynamic-datasource-example

在springboot2.0下最简单集成多数据源的方案。

  1. 引入dynamic-datasource-spring-boot-starter。
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  <version>1.0.0</version>
</dependency>
  1. 配置主从数据源。

spring.datasource.dynamic.master 配置唯一主数据源(写库)

spring.datasource.dynamic.slaves 配置每一个从数据源(读库)

spring:
  datasource:
    dynamic:
      master:
        username: root
        password: 123456
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://47.100.20.186:3307/dynamic?characterEncoding=utf8&useSSL=false
      slaves:
        one:
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
          url: jdbc:mysql://47.100.20.186:3308/dynamic?characterEncoding=utf8&useSSL=false
        two:
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
          url: jdbc:mysql://47.100.20.186:3309/dynamic?characterEncoding=utf8&useSSL=false
  1. 切换数据源。

使用 @DS 注解切换数据源。

可以注解在方法上,可以注解在service实现或mapper接口方法上。

注解 结果
没有@DS 主库
@DS("slave") 存在slave指定slave,不存在主库
@DS 根据DynamicDataSourceStrategy策略,选择一个从库。默认负载均衡策略。

读写分离

引入 mybatis-plus sharding-jdbc 依赖

点击参考

yaml 配置

sharding:
  jdbc:
    datasource:
      names: ds_master,ds_slave_0,ds_slave_1
      ds_master:
        ...
      ds_slave_0:
        ...
      ds_slave_1:
        ...
    config:
      masterslave:
        load-balance-algorithm-type: round_robin
        name: ds_ms
        master-data-source-name: ds_master
        slave-data-source-names: ds_slave_0,ds_slave_1

多数据源使用 shardingjdbc 实现

点击 mybatisplus-sharding-jdbc 查看

多数据源使用 Spring AbstractRoutingDataSource 实现

第一步:扩展Spring的AbstractRoutingDataSource抽象类,实现动态数据源。 AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是实现数据源的route的核心,这里对该方法进行Override。 【上下文DbContextHolder为一线程安全的ThreadLocal】具体代码如下:

public class DynamicDataSource extends AbstractRoutingDataSource {

/**
 * 取得当前使用哪个数据源
 * @return
 */
@Override
protected Object determineCurrentLookupKey() {
    return DbContextHolder.getDbType();
}
}

public class DbContextHolder {
private static final ThreadLocal contextHolder = new ThreadLocal<>();

/**
 * 设置数据源
 * @param dbTypeEnum
 */
public static void setDbType(DBTypeEnum dbTypeEnum) {
    contextHolder.set(dbTypeEnum.getValue());
}

/**
 * 取得当前数据源
 * @return
 */
public static String getDbType() {
    return contextHolder.get();
}

/**
 * 清除上下文数据
 */
public static void clearDbType() {
    contextHolder.remove();
}
}

public enum DBTypeEnum {
one("dataSource_one"), two("dataSource_two");
private String value;

DBTypeEnum(String value) {
    this.value = value;
}

public String getValue() {
    return value;
}
}

第二步:配置动态数据源将DynamicDataSource Bean加入到Spring的上下文xml配置文件中去,同时配置DynamicDataSource的targetDataSources(多数据源目标)属性的Map映射。 代码如下【我省略了dataSource_one和dataSource_two的配置】:

<bean id="dataSource" class="com.miyzh.dataclone.db.DynamicDataSource">
    <property name="targetDataSources">
        <map key-type="java.lang.String">
            <entry key="dataSource_one" value-ref="dataSource_one" />
            <entry key="dataSource_two" value-ref="dataSource_two" />
        </map>
    </property>
    <property name="defaultTargetDataSource" ref="dataSource_two" />
</bean>

第三步:使用动态数据源:DynamicDataSource是继承与AbstractRoutingDataSource,而AbstractRoutingDataSource又是继承于org.springframework.jdbc.datasource.AbstractDataSource,AbstractDataSource实现了统一的DataSource接口,所以DynamicDataSource同样可以当一个DataSource使用。

@Test 
public void test() {
DbContextHolder.setDbType(DBTypeEnum.one);
List userList = iUserService.selectList(new EntityWrapper());
for (User user : userList) {
log.debug(user.getId() + "#" + user.getName() + "#" + user.getAge());
}

    DbContextHolder.setDbType(DBTypeEnum.two);
    List<IdsUser> idsUserList = iIdsUserService.selectList(new EntityWrapper<IdsUser>());
    for (IdsUser idsUser : idsUserList) {
        log.debug(idsUser.getMobile() + "#" + idsUser.getUserName());
    }
}  

!> 说明:

  • 1、事务管理:使用动态数据源的时候,可以看出和使用单数据源的时候相比,在使用配置上几乎没有差别,在进行性事务管理配置的时候也没有差别:
  • 2、通过扩展Spring的AbstractRoutingDataSource可以很好的实现多数据源的rout效果,而且对扩展更多的数据源有良好的伸缩性,只要增加数据源和修改DynamicDataSource的targetDataSources属性配置就好。在数据源选择控制上,可以采用手动控制(业务逻辑并不多的时候),也可以很好的用AOP的@Aspect在Service的入口加入一个切面@Pointcut,在@Before里判断JoinPoint的类容选定特定的数据源。