沃梦达 / IT编程 / 数据库 / 正文

springboot2+mybatis多种方式实现多数据配置方法

下面我将给出详细的“springboot2+mybatis多种方式实现多数据配置方法”的攻略,包含以下内容:

下面我将给出详细的“springboot2+mybatis多种方式实现多数据配置方法”的攻略,包含以下内容:

  1. 环境配置
  2. 多数据源引入方式
  3. 多数据源的实现

1. 环境配置

首先,我们需要在pom.xml文件中引入springboot-mybatis-starter,可以使用如下配置:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>

同时,如果需要连接多个数据源,也需要在pom.xml文件中引入对应的数据库驱动:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 这里可以引入多个数据库驱动,以实现对多个不同的数据源的支持 -->

2. 多数据源引入方式

接着,我们需要在SpringBoot的配置文件application.properties或application.yml中进行多数据源的配置,并且在代码中使用对应的数据源进行操作。我们可以使用多种方式来实现多数据源的配置:

2.1 使用SpringBoot2提供的多配置文件方式

  • 在resources目录下新建application-dev.properties和application-prod.properties,并分别配置对应的数据库信息,如下所示:
# application-dev.properties
spring.datasource.url=jdbc:mysql://localhost:3306/db1?useSSL=false
spring.datasource.username=root
spring.datasource.password=123456

# application-prod.properties
spring.datasource.url=jdbc:mysql://localhost:3306/db2?useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
  • 在SpringBoot主启动类中,使用@ConfigurationProperties(prefix = “spring.datasource”)注解,将application.properties或application.yml中的数据库配置映射到DataSource对象中:
@Configuration
@MapperScan(basePackages = "com.example.dao")
public class DataSourceConfig {

    @Bean(name = "devDataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource devDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "prodDataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource prodDataSource() {
        return DataSourceBuilder.create().build();
    }
}

@SpringBootApplication
public class MultiDatasourceApplication {

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

}
  • 在具体的操作类中,使用@Qualifier注解指定使用哪个数据源:
@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    @Qualifier("devDataSource")
    private DataSource devDataSource;

    @Autowired
    @Qualifier("prodDataSource")
    private DataSource prodDataSource;

    @Autowired
    private UserMapper userMapper;

    @Override
    public User getUserById(Long id) {
        User user;
        if (id < 100) {
            // 使用devDataSource数据源
            user = userMapper.selectByPrimaryKey(id, devDataSource);
        } else {
            // 使用prodDataSource数据源
            user = userMapper.selectByPrimaryKey(id, prodDataSource);
        }

        return user;
    }
}

2.2 使用SpringBoot2提供的多Profile方式

  • 在SpringBoot主启动类中,使用spring.profiles.active属性指定当前使用的配置文件,如下所示:
@SpringBootApplication
public class MultiDatasourceApplication {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(MultiDatasourceApplication.class);
        app.setAdditionalProfiles("dev"); // 指定使用dev配置文件
        // app.setAdditionalProfiles("prod"); // 指定使用prod配置文件
        app.run(args);
    }

}
  • 在配置文件中,针对不同的配置文件,指定不同的数据源信息,如下所示:
# application.yml
spring:
  profiles:
    active: prod

---

# application-dev.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/db1?useSSL=false
    username: root
    password: 123456

---

# application-prod.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/db2?useSSL=false
    username: root
    password: 123456
  • 采用与2.1中相似的方式对具体的操作类进行注入和使用。

3. 多数据源的实现

了解了多种数据源的配置方式后,接下来我们来了解如何实现多数据源的操作。

3.1 使用Spring的AbstractRoutingDataSource实现动态数据源

  • 实现一个继承AbstractRoutingDataSource的动态数据源类,重写determineCurrentLookupKey方法,根据当前的线程,动态切换数据源:
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceKey();
    }

}
  • 创建一个数据源的上下文类,通过ThreadLocal来保存当前的数据源key:
public class DataSourceContextHolder {

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

    public static void setDataSourceKey(String dataSourceKey) {
        CONTEXT_HOLDER.set(dataSourceKey);
    }

    public static String getDataSourceKey() {
        return CONTEXT_HOLDER.get();
    }

    public static void clearDataSourceKey() {
        CONTEXT_HOLDER.remove();
    }
}
  • 在SpringBoot配置类中,创建两个DataSource对象,分别指定不同的数据源信息:
@Configuration
@MapperScan(basePackages = "com.example.dao")
public class DataSourceConfig {

    @Bean(name = "devDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.dev")
    public DataSource devDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "prodDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.prod")
    public DataSource prodDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "dynamicDataSource")
    public DataSource dynamicDataSource(@Qualifier("devDataSource") DataSource devDataSource,
                                         @Qualifier("prodDataSource") DataSource prodDataSource) {
        Map<Object, Object> targetDataSource = new HashMap<>();
        targetDataSource.put("dev", devDataSource);
        targetDataSource.put("prod", prodDataSource);
        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSource);
        dataSource.setDefaultTargetDataSource(devDataSource);
        return dataSource;
    }

}
  • 在需要动态切换数据源的操作类中,使用@Autowired注解直接注入DynamicDataSource即可:
@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private DynamicDataSource dynamicDataSource;

    @Autowired
    private UserMapper userMapper;

    @Override
    public User getUserById(Long id) {
        if (id < 100) {
            // 切换到dev数据源
            DataSourceContextHolder.setDataSourceKey("dev");
        } else {
            // 切换到prod数据源
            DataSourceContextHolder.setDataSourceKey("prod");
        }

        User user = userMapper.selectByPrimaryKey(id);
        DataSourceContextHolder.clearDataSourceKey();

        return user;
    }
}

参考示例代码:https://github.com/Ricardo-LiPeng/springboot-mybatis-multipledatasource

3.2 使用注解和AOP实现动态数据源

  • 在动态切换数据源的注解类中,使用自定义注解@TargetDataSource来指定需要使用的数据源key:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface TargetDataSource {
    String value() default "";
}
  • 创建一个AOP切面类,在切面中动态切换数据源:
@Aspect
@Component
public class DynamicDataSourceAspect {

    @Before("@annotation(ds)")
    public void beforeSwitchDS(JoinPoint point, TargetDataSource ds) {
        String dataSourceValue = ds.value();
        if (StringUtils.isEmpty(dataSourceValue)) {
            // 没有指定数据源key,使用默认数据源
            DataSourceContextHolder.setDataSourceKey("dev");
        } else {
            DataSourceContextHolder.setDataSourceKey(dataSourceValue);
        }
    }

    @After("@annotation(ds)")
    public void afterSwitchDS(JoinPoint point, TargetDataSource ds) {
        DataSourceContextHolder.clearDataSourceKey();
    }

}
  • 在需要动态切换数据源的操作类中,使用自定义注解@TargetDataSource来指定需要使用的数据源key:
@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @TargetDataSource("prod") // 指定使用prod数据源
    @Override
    public User getUserById(Long id) {
        return userMapper.selectByPrimaryKey(id);
    }
}

参考示例代码:https://github.com/Ricardo-LiPeng/springboot-mybatis-multipledatasource/tree/master/springboot-mybatis-multipledatasource-annotation方式

本文标题为:springboot2+mybatis多种方式实现多数据配置方法