SpringBoot整合多数据源

项目开发中,往往需要从多个数据库(源)中取数的场景。

本文演示SpringBoot整合多数据源,并基于自定义注解形式和大家一起学习基本使用。

一、项目搭建

新建一个SpringBoot项目,引入依赖:

sql 复制代码
<properties>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>8.0.22</scope>
        </dependency>

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

        <!--swagger配置-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.8.0</version>
        </dependency>

        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.9.6</version>
        </dependency>

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

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

二、配置文件及库表准备

①配置文件:

java 复制代码
server:
  port: 8088

spring:
  datasource:
    jdbc-url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: ********
    password: ********
    driver-class: com.mysql.cj.jdbc.Driver
    db2:
      jdbc-url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
      username: ********
      password: ********
      driver-class: com.mysql.cj.jdbc.Driver
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.demo.mapper

②库表准备:

三、编码实现

①自定义注解相关类

java 复制代码
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    //指定默认数据源
    DataSourceType value() default DataSourceType.DS_ONE;
}

//切面类
@Aspect
@Order(1)
@Component
public class DataSourceAspect {
    /**
     * TODO 基于项目路径需要调整
     */
    @Pointcut("@annotation(com.example.demo.config.DataSource)")
    public void dsPointCut() {
    }
 
    @Around("dsPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        DataSource dataSource = method.getAnnotation(DataSource.class);
        if (dataSource != null) {
            DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
        }
        try {
            return point.proceed();
        } finally {
            DynamicDataSourceContextHolder.clearDataSourceType();
        }
    }
}

//配置类
@Configuration
public class DataSourceConfig {
 
    @Bean
    @ConfigurationProperties("spring.datasource")
    public DataSource db1DataSource() {
        return DataSourceBuilder.create().build();
    }
 
    @Bean
    @ConfigurationProperties("spring.datasource.db2")
    public DataSource db2DataSource() {
        return DataSourceBuilder.create().build();
    }
 
    @Bean(name = "dynamicDataSource")
    @Primary
    public DynamicDataSource dataSource(DataSource db1DataSource, DataSource db2DataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>(4);
        targetDataSources.put(DataSourceType.DS_ONE.name(), db1DataSource);
        targetDataSources.put(DataSourceType.DS_TWO.name(), db2DataSource);
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 注入目标数据源,可以是多个
        dynamicDataSource.setTargetDataSources(targetDataSources);
        // 注入默认数据源,只能是一个
        dynamicDataSource.setDefaultTargetDataSource(db1DataSource);
        return dynamicDataSource ;
    }
}

//枚举类
public enum DataSourceType {
    DS_ONE,
    DS_TWO
}

//获取多数据源
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }
}

//上下文
public class DynamicDataSourceContextHolder {
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    public static void setDataSourceType(String dataSourceType){
        CONTEXT_HOLDER.set(dataSourceType);
    }

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

    public static void clearDataSourceType(){
        CONTEXT_HOLDER.remove();
    }
}

②swagger配置

java 复制代码
@Configuration
@EnableSwagger2
public class Swagger2Configure {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
                .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
                .paths(PathSelectors.any()).build();
    }
    /**
     * 展示信息
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder().title("api文档")
                .version("1.0").build();
    }
}

③访问层

java 复制代码
@Api(tags = "多数据源测试")
@RestController
public class TestController {

    @Autowired
    private TestService testService;

    @ApiOperation("test")
    @PostMapping("/list")
    public UserAndProjectVO test(){
        return testService.list();
    }
}

④服务层

java 复制代码
public interface TestService {

    /**
     * 多数据源获取数据
     * @return
     */
    UserAndProjectVO list();
}
//调用服务
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private UserService userService;

    @Autowired
    private ProjectService projectService;

    @Override
    public UserAndProjectVO list() {
        return UserAndProjectVO.builder()
                .users(userService.list())
                .projects(projectService.list())
                .build();
    }
}

//user服务
public interface UserService {
    /**
     * DB1获取用户数据
     * @return
     */
    List<User> list();
}

//user服务实现层
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    /**
     * @DataSource(value = DataSourceType.DS_ONE)
     * 默认数据源,可以不使用注解
     */
    public List<User> list() {
        return userMapper.list();
    }
}

//project服务
public interface ProjectService {
    /**
     * DB2获取项目数据
     * @return
     */
    List<Project> list();
}

//project服务实现层
@Service
public class ProjectServiceImpl implements ProjectService {
    @Autowired
    private ProjectMapper projectMapper;

    @Override
    @DataSource(value = DataSourceType.DS_TWO)
    public List<Project> list() {
        return projectMapper.list();
    }

}

⑤持久层

java 复制代码
@Repository
public interface UserMapper {
    /**
     * DB1获取用户数据
     * @return
     */
    List<User> list();
}



@Repository
public interface ProjectMapper {
    /**
     * DB2获取项目数据
     * @return
     */
    List<Project> list();

}

⑥实体层

java 复制代码
//user实体
@Data
public class User {
    private Integer id;
    private String name;
}


//project实体
@Data
public class Project {
    private Integer id;
    private String name;
}

⑦映射文件

XML 复制代码
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <resultMap id="BaseResultMap" type="com.example.demo.entity.User" >
        <id column="id" property="id" jdbcType="BIGINT" />
        <result column="name" property="name" jdbcType="VARCHAR" />
    </resultMap>
    <select id="list" resultMap="BaseResultMap">
        select id,name from user;
    </select>
</mapper>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.ProjectMapper">
    <resultMap id="BaseResultMap" type="com.example.demo.entity.Project" >
        <id column="id" property="id" jdbcType="BIGINT" />
        <result column="name" property="name" jdbcType="VARCHAR" />
    </resultMap>
    <select id="list" resultMap="BaseResultMap">
        select id,name from project;
    </select>
</mapper>

⑧启动类

java 复制代码
@EnableSwagger2
@EnableSwaggerBootstrapUI
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext application = SpringApplication.run(DemoApplication.class, args);
        Environment env = application.getEnvironment();
        String ip = "localhost";
        String port = env.getProperty("server.port");
        log.info("\n----------------------------------------------------------\n\t" +
                "Application  is running! Access URLs:\n\t" +
                "Local: \t\thttp://localhost:" + port  + "/\n\t" +
                "External: \thttp://" + ip + ":" + port  + "/\n\t" +
                "Doc: \t\thttp://" + ip + ":" + port + "/swagger-ui.html\n" +
                "----------------------------------------------------------");
    }

}

四、测试

至此,SpringBoot整合多数据源演示完毕。

相关推荐
情勤坊11 分钟前
JAVA实现将PDF转换成word文档
java·pdf·word
苹果酱056712 分钟前
springcloud-网关路由gateway
java·开发语言·spring boot·mysql·中间件
武子康18 分钟前
Java-08 深入浅出 MyBatis - 多对多模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据库·sql·mybatis
摇滚侠26 分钟前
java http body的格式 ‌application/x-www-form-urlencoded‌不支持文件上传
java·开发语言·http
尘浮生1 小时前
Java项目实战II基于SpringBoot的共享单车管理系统开发文档+数据库+源码)
java·开发语言·数据库·spring boot·后端·微信小程序·小程序
huaxiaorong1 小时前
如何将旧的Android手机改造为家用服务器
后端
2401_857439691 小时前
社团管理新工具:SpringBoot框架
java·spring boot·后端
2401_857610031 小时前
Spring Boot OA:企业办公自动化的创新之路
spring boot·后端·mfc
难念的码1 小时前
Skill 语言语法基础
人工智能·后端
ThetaarSofVenice1 小时前
Java从入门到放弃 之 泛型
java·开发语言