当前位置: > > > SpringBoot - 使用Spring Data JPA操作数据库2(多数据源的配置与使用)

SpringBoot - 使用Spring Data JPA操作数据库2(多数据源的配置与使用)

    所谓多数据源,就是一个 Java EE 项目中采用了不同数据库实例中的多个库,或者同一个数据库实例中多个不同的库。JPAMyBatis 配置多数据源类似(点击查看),不同的是,JPA 配置时主要提供不同的 LocalContainerEntityManagerFactoryBean 以及事务管理器,具体配置步骤如下。

三、多数据源的配置与使用

1,添加依赖

首先编辑 pom.xml 文件,添加相关依赖:
注意:跟前文相比,这里的数据库连接池依赖改用 druid-spring-boot-starterdruid-spring-boot-starter 可以帮助开发者在 Spring Boot 项目中轻松集成 Druid 数据库连接池和监控。
<!-- Spring Data JPA 依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!-- 数据库驱动依赖 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

<!-- 数据库连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>

2,配置数据库链接

(1)假设我们需要同时连接如下 hanggehangge2 这两个数据库。

(2)在 application.properties 中配置数据库连接信息,以及 JPA 相关的配置:
注意:这里的 JPA 配置与单独数据库的 JPA 有区别,因为后面的配置中要从 JpaProperties 中的 getProperties 方法中获取所有 JPA 相关的配置,因此这里的属性前缀都是 spring.jpa.properties
# 数据源 1
spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.one.url=jdbc:mysql://localhost:3306/hangge
spring.datasource.one.username=root
spring.datasource.one.password=hangge1234
# 数据源 2
spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.two.url=jdbc:mysql://localhost:3306/hangge2
spring.datasource.two.username=root
spring.datasource.two.password=hangge1234

#是否在控制台打印JPA执行过程生成的SQL
spring.jpa.properties.show-sql=true
#表示JPA对应的数据库是MySQL
spring.jpa.properties.database=mysql
#表示在项目启动时根据实体类更新数据库中的表
spring.jpa.properties.hibernate.hbm2ddl.auto=update
#表示使用的数据库方言是MySQL57Dialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect

3,配置数据源

创建 DataSourceConfig 配置数据源,根据 application.properties  中的配置生成两个数据源:
代码说明:
  • DataSourceConfig 中提供了两个数据源:dsOnedsTwo ,默认方法名即为实例名。
  • @ConfigurationProperties 注解表示使用不同前缀的配置文件来创建不同的 DataSource 实例。
  • 注意:在第一个 DataSource 上还标注了 @Primary 注解。否则程序启动时会报 Parameter 0 of method entityManagerFactoryBeanOne in com.example.demo.config.JpaConfigOne required a bean of type 'org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder' that could not be found. 错误
@Configuration
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties("spring.datasource.one")
    @Primary
    DataSource dsOne() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.two")
    DataSource dsTwo() {
        return DruidDataSourceBuilder.create().build();
    }
}

4,创建 JPA 配置

(1)接下需要根据两个配置好的数据源创建两个不同的 JPA 配置。第一个 JPA 配置如下:
(1)使用 @EnableTransactionManagement 注解来进行 JPA 的配置,该注解中主要配置了三个属性:
  • basePackages 用来指定 Repository 所在的位置。
  • entityManagerFactoryRef 用来指定实体类管理工厂 Bean 的名称。
  • transactionManagerRef 用来指定事物管理器的引用名称,这里的引用名称就是 JpaConfigOne 类中注册的 Bean 的名称(默认的 Bean 名称为方法名)
(2)配置类中第一个方法创建 LocalContainerEntityManagerFactoryBean,该 Bean 将用来提供 EntityManager 实例,创建过程如下:
  • 首先配置数据源
  • 然后设置 JPA 相关配置(JpaProperties 由系统自动加载)
  • 再设置实体类所在的位置。
  • 最后配置持久化单元名。若项目中只有一个 EntityManagerFactory,则 persistenceUnit 可以省略掉,若有多个,则必须明确指定持久化单元名。
(3)由于项目中我们会提供两个 LocalContainerEntityManagerFactoryBean 实例(JpaConfigOne 里一个、JpaConfigTwo 里一个),因此我们需要在 JpaConfigOne 里的 LocalContainerEntityManagerFactoryBean 实例上添加 @Primary 注解,表示当存在多个 LocalContainerEntityManagerFactoryBean 实例时,该实例将被优先使用。
(4)配置类中第二个方法表示创建一个事务管理器。JpaTransactionManager 提供对单个 EntityManagerFactory 的事务支持,专门用于解决 JPA 中的事务管理。
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.demo.dao1",
        entityManagerFactoryRef = "entityManagerFactoryBeanOne",
        transactionManagerRef = "platformTransactionManagerOne")
public class JpaConfigOne {
    @Resource(name = "dsOne")
    DataSource dsOne;

    @Autowired
    JpaProperties jpaProperties;

    @Bean
    @Primary
    LocalContainerEntityManagerFactoryBean entityManagerFactoryBeanOne(
            EntityManagerFactoryBuilder builder) {
        return builder.dataSource(dsOne)
                .properties(jpaProperties.getProperties())
                .packages("com.example.demo.bean")
                .persistenceUnit("pu1")
                .build();
    }

    @Bean
    PlatformTransactionManager platformTransactionManagerOne(
            EntityManagerFactoryBuilder builder) {
        LocalContainerEntityManagerFactoryBean factoryOne
                = entityManagerFactoryBeanOne(builder);
        return new JpaTransactionManager(factoryOne.getObject());
    }
}

(2)第二个 JPA 配置如下:
JpaConfigTwo 的配置与 JpaConfigOne 类似,主要区别在于 LocalContainerEntityManagerFactoryBean 实例不需要添加 @Primary 注解。
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.demo.dao2",
        entityManagerFactoryRef = "entityManagerFactoryBeanTwo",
        transactionManagerRef = "platformTransactionManagerTwo")
public class JpaConfigTwo {
    @Resource(name = "dsTwo")
    DataSource dsTwo;

    @Autowired
    JpaProperties jpaProperties;

    @Bean
    LocalContainerEntityManagerFactoryBean entityManagerFactoryBeanTwo(
            EntityManagerFactoryBuilder builder) {
        return builder.dataSource(dsTwo)
                .properties(jpaProperties.getProperties())
                .packages("com.example.demo.bean")
                .persistenceUnit("pu2")
                .build();
    }

    @Bean
    PlatformTransactionManager platformTransactionManagerTwo(
            EntityManagerFactoryBuilder builder) {
        LocalContainerEntityManagerFactoryBean factoryTwo
                = entityManagerFactoryBeanTwo(builder);
        return new JpaTransactionManager(factoryTwo.getObject());
    }
}

5,创建  Repository(数据库访问层)

    根据上面第 4 步的配置,我们分别在 com.example.demo.dao1 com.example.demo.dao2 包下创建两个 Repository,分别用于操作不同的数据源。
  • BookDao1 内容如下:
package com.example.demo.dao1;

import com.example.demo.bean.Book;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BookDao1 extends JpaRepository<Book, Integer> {
}

  • BookDao2 内容如下:
package com.example.demo.dao2;

import com.example.demo.bean.Book;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BookDao2 extends JpaRepository<Book, Integer> {
}

6,创建 Controller

    为方便演示,这里省略了 Service 层,将 BookDao1BookDao2 直接注入到 Controller 中使用:分别向两个数据库中各插入一条数据。
@RestController
public class HelloController {

    @Autowired
    BookDao1 bookDao1;

    @Autowired
    BookDao2 bookDao2;

    @RequestMapping("/test")
    public void test() {
        // 往第一个数据库中插入数据
        Book book1 = new Book();
        book1.setName("时间的秩序");
        book1.setAuthor("卡洛·罗韦利");
        book1.setPrice(56f);
        bookDao1.save(book1); //使用save方法将数据保存到数据库

        // 往第二个数据库中插入数据
        Book book2 = new Book();
        book2.setName("发条橙");
        book2.setAuthor("安东尼·伯吉斯 ");
        book2.setPrice(22f);
        bookDao2.save(book2); //使用save方法将数据保存到数据库
    }

7,运行测试

在浏览器中访问 http://localhost:8080/test 地址,可以看到两个数据库中的表和数据都已经存在了。

评论0