Spring Data JPA 实战 - JPA配置多个数据源

在Spring Data JPA中配置多个数据源是一种常见的需求,尤其是在微服务架构或者需要同时操作多个数据库的场景下。配置多个数据源涉及到多个DataSource实例的定义以及与之对应的EntityManagerFactory的设置。下面我将详细介绍如何在Spring Boot应用中配置多个数据源,并使用这些数据源与Spring Data JPA结合进行数据访问。

1. 添加依赖

确保你的项目中有Spring Data JPA和Spring Boot Starter Web的依赖。如果你使用的是Maven,可以添加以下依赖到pom.xml文件中:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- MySQL驱动依赖 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!-- PostgreSQL驱动依赖 -->
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

2. 配置数据源

你需要为每个数据源定义一个DataSource实例。可以通过application.properties或Java配置类来完成配置。

2.1 使用application.properties配置数据源

application.properties文件中配置两个数据源的信息。

# application.properties
# MySQL data source configuration
spring.datasource.db1.url=jdbc:mysql://localhost:3306/db1
spring.datasource.db1.username=db1user
spring.datasource.db1.password=db1pass
spring.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver

# PostgreSQL data source configuration
spring.datasource.db2.url=jdbc:postgresql://localhost:5432/db2
spring.datasource.db2.username=db2user
spring.datasource.db2.password=db2pass
spring.datasource.db2.driver-class-name=org.postgresql.Driver
2.2 使用Java配置类配置数据源

通过Java配置类来定义DataSource实例。

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {

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

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

3. 配置EntityManagerFactory

对于每个数据源,你需要配置一个EntityManagerFactory。这可以通过LocalContainerEntityManagerFactoryBean来完成。

3.1 使用Java配置类配置EntityManagerFactory
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
public class JpaConfig {

    @Bean(name = "entityManagerFactory1")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory1(@Qualifier("dataSource1") DataSource dataSource1) {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource1);
        emf.setPackagesToScan("com.example.demo.entity.db1");

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        emf.setJpaVendorAdapter(vendorAdapter);
        emf.setJpaProperties(additionalProperties());

        return emf;
    }

    @Bean(name = "entityManagerFactory2")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory2(@Qualifier("dataSource2") DataSource dataSource2) {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource2);
        emf.setPackagesToScan("com.example.demo.entity.db2");

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        emf.setJpaVendorAdapter(vendorAdapter);
        emf.setJpaProperties(additionalProperties());

        return emf;
    }

    Properties additionalProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", "update");
        properties.setProperty("hibernate.show_sql", "true");
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        return properties;
    }
}

4. 配置TransactionManager

对于每个EntityManagerFactory,你需要配置一个TransactionManager

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;

import javax.persistence.EntityManagerFactory;

@Configuration
public class TransactionManagerConfig {

    @Bean(name = "transactionManager1")
    public JpaTransactionManager transactionManager1(@Qualifier("entityManagerFactory1") EntityManagerFactory emf1) {
        return new JpaTransactionManager(emf1);
    }

    @Bean(name = "transactionManager2")
    public JpaTransactionManager transactionManager2(@Qualifier("entityManagerFactory2") EntityManagerFactory emf2) {
        return new JpaTransactionManager(emf2);
    }
}

5. 创建实体类

为每个数据源创建对应的实体类。

// For db1
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity(name = "Product1")
public class Product1 {

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

    private String name;

    private double price;

    // Getters and setters
}

// For db2
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity(name = "Product2")
public class Product2 {

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

    private String name;

    private double price;

    // Getters and setters
}

6. 创建Repository接口

为每个实体类创建对应的Repository接口。

// For db1
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductRepository1 extends JpaRepository<Product1, Long> {
}

// For db2
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductRepository2 extends JpaRepository<Product2, Long> {
}

7. 创建Service类

在Service层中注入对应的Repository,并使用它们进行数据访问。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class ProductService {

    private final ProductRepository1 productRepository1;
    private final ProductRepository2 productRepository2;

    @Autowired
    public ProductService(ProductRepository1 productRepository1, ProductRepository2 productRepository2) {
        this.productRepository1 = productRepository1;
        this.productRepository2 = productRepository2;
    }

    @Transactional(transactionManager = "transactionManager1")
    public void createProduct1(String name, double price) {
        Product1 product = new Product1();
        product.setName(name);
        product.setPrice(price);
        productRepository1.save(product);
    }

    @Transactional(transactionManager = "transactionManager2")
    public void createProduct2(String name, double price) {
        Product2 product = new Product2();
        product.setName(name);
        product.setPrice(price);
        productRepository2.save(product);
    }

    @Transactional(readOnly = true, transactionManager = "transactionManager1")
    public List<Product1> getAllProducts1() {
        return productRepository1.findAll();
    }

    @Transactional(readOnly = true, transactionManager = "transactionManager2")
    public List<Product2> getAllProducts2() {
        return productRepository2.findAll();
    }
}

8. 创建Controller

创建Controller来处理HTTP请求,并使用Service层的方法进行数据访问。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/products")
public class ProductController {

    private final ProductService productService;

    @Autowired
    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @PostMapping("/db1")
    public void createProduct1(@RequestParam String name, @RequestParam double price) {
        productService.createProduct1(name, price);
    }

    @PostMapping("/db2")
    public void createProduct2(@RequestParam String name, @RequestParam double price) {
        productService.createProduct2(name, price);
    }

    @GetMapping("/db1")
    public List<Product1> getAllProducts1() {
        return productService.getAllProducts1();
    }

    @GetMapping("/db2")
    public List<Product2> getAllProducts2() {
        return productService.getAllProducts2();
    }
}

9. 总结

通过上述步骤,我们成功地配置了两个数据源,并为每个数据源定义了对应的EntityManagerFactoryTransactionManager以及Repository接口。这种方式使得Spring Boot应用能够同时操作多个数据库,并保持数据的一致性和事务的正确性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值