Java中的多数据源管理:如何在单个应用中集成多数据库

大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在现代软件架构中,应用往往需要访问多个数据库以支持不同的业务需求。本文将介绍如何在Java应用中实现多数据源管理,包括配置、使用和切换数据源的最佳实践。

一、多数据源的需求分析

多数据源管理的需求通常来自以下几种场景:

  1. 分离读写操作:为了提高性能,主库用于写操作,从库用于读操作。
  2. 不同的数据库类型:例如,关系型数据库与NoSQL数据库的组合。
  3. 微服务架构:每个微服务可能使用独立的数据源。

二、技术栈选择

在实现多数据源管理时,以下技术栈是常见的选择:

  • Spring Boot:用于简化应用的配置和开发。
  • Spring Data JPA:提供统一的数据访问层。
  • HikariCP:高性能的JDBC连接池。

三、配置多数据源

首先,确保你的pom.xml中添加必要的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

接下来,在application.yml中配置多个数据源:

spring:
  datasource:
    primary:
      jdbc-url: jdbc:mysql://localhost:3306/primary_db
      username: root
      password: password
      driver-class-name: com.mysql.cj.jdbc.Driver
      hikari:
        maximum-pool-size: 10
    secondary:
      jdbc-url: jdbc:mysql://localhost:3306/secondary_db
      username: root
      password: password
      driver-class-name: com.mysql.cj.jdbc.Driver
      hikari:
        maximum-pool-size: 10

四、数据源配置类

创建一个配置类,定义数据源和实体管理器:

package cn.juwatech.config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;

@Configuration
@EnableJpaRepositories(
        basePackages = "cn.juwatech.repository.primary",
        entityManagerFactoryRef = "primaryEntityManagerFactory",
        transactionManagerRef = "primaryTransactionManager"
)
public class PrimaryDataSourceConfig {

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

    @Primary
    @Bean(name = "primaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(primaryDataSource())
                .packages("cn.juwatech.entity.primary")
                .persistenceUnit("primary")
                .build();
    }

    @Primary
    @Bean(name = "primaryTransactionManager")
    public DataSourceTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

再创建一个类似的配置类用于配置第二个数据源:

package cn.juwatech.config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;

@Configuration
@EnableJpaRepositories(
        basePackages = "cn.juwatech.repository.secondary",
        entityManagerFactoryRef = "secondaryEntityManagerFactory",
        transactionManagerRef = "secondaryTransactionManager"
)
public class SecondaryDataSourceConfig {

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

    @Bean(name = "secondaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(secondaryDataSource())
                .packages("cn.juwatech.entity.secondary")
                .persistenceUnit("secondary")
                .build();
    }

    @Bean(name = "secondaryTransactionManager")
    public DataSourceTransactionManager secondaryTransactionManager(@Qualifier("secondaryDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

五、实体类与仓库接口

根据数据源创建不同的实体类和仓库接口。以下是一个主数据源的实体类及其对应的仓库:

package cn.juwatech.entity.primary;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class PrimaryEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    // Getters and Setters
}

对应的仓库接口:

package cn.juwatech.repository.primary;

import cn.juwatech.entity.primary.PrimaryEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PrimaryEntityRepository extends JpaRepository<PrimaryEntity, Long> {
}

同样地,为第二个数据源的实体类和仓库定义类似的类。

六、服务层的实现

在服务层中,我们可以根据需求选择不同的数据源进行操作。以下是一个服务类示例:

package cn.juwatech.service;

import cn.juwatech.entity.primary.PrimaryEntity;
import cn.juwatech.entity.secondary.SecondaryEntity;
import cn.juwatech.repository.primary.PrimaryEntityRepository;
import cn.juwatech.repository.secondary.SecondaryEntityRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MultiDataSourceService {

    @Autowired
    private PrimaryEntityRepository primaryEntityRepository;

    @Autowired
    private SecondaryEntityRepository secondaryEntityRepository;

    public PrimaryEntity savePrimaryEntity(PrimaryEntity entity) {
        return primaryEntityRepository.save(entity);
    }

    public SecondaryEntity saveSecondaryEntity(SecondaryEntity entity) {
        return secondaryEntityRepository.save(entity);
    }
}

七、控制器的实现

最后,在控制器中实现对服务的调用:

package cn.juwatech.controller;

import cn.juwatech.entity.primary.PrimaryEntity;
import cn.juwatech.entity.secondary.SecondaryEntity;
import cn.juwatech.service.MultiDataSourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class MultiDataSourceController {

    @Autowired
    private MultiDataSourceService multiDataSourceService;

    @PostMapping("/primary")
    public PrimaryEntity createPrimary(@RequestBody PrimaryEntity entity) {
        return multiDataSourceService.savePrimaryEntity(entity);
    }

    @PostMapping("/secondary")
    public SecondaryEntity createSecondary(@RequestBody SecondaryEntity entity) {
        return multiDataSourceService.saveSecondaryEntity(entity);
    }
}

八、测试与验证

可以使用Postman或其他工具测试API,验证是否能够成功操作不同数据源的数据。

  1. /api/primary发送POST请求,数据将保存到主数据库。
  2. /api/secondary发送POST请求,数据将保存到第二数据库。

总结

通过以上步骤,我们成功地在Java应用中实现了多数据源管理。可以根据业务需求扩展此方案,例如使用不同类型的数据库,或者在微服务架构中灵活切换数据源。借助Spring Boot的强大功能和灵活配置,我们可以轻松管理和访问多个数据库,为复杂应用提供强有力的支持。