使用 Spring Data JDBC 和 CrudRepository 接口的多个数据源

use*_*410 8 spring spring-boot spring-data-jdbc

我有一个重要的问题:

我的情况:

  • 使用Spring Data JDBC
  • 使用两个数据库
  • 的用法 CrudRepository

正如你可以看到这里春天JDBC数据可以extends CrudRepository与获得春天所有CRUD操作开箱-没有明确的执行!

这是一个简单的 4 步过程:

  1. 定义你的属性
  2. 定义你的实体
  3. 定义一个扩展 CrudRepository 的接口和
  4. 使用该接口

但是在使用两个数据库的情况下,有一个 5. 步骤,您必须在其中定义一个@Configuration类。

我做了这5个步骤如下:

0. pom.xml

 <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <groupId>org.junit.vintage</groupId>
          <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencies>
Run Code Online (Sandbox Code Playgroud)

1. 定义你的属性

应用程序属性

## D1
datasource.db1.driverClassName=...
datasource.db1.username=...
datasource.db1.password=...
datasource.db1.jdbcUrl=...
## D2
datasource.db2.driverClassName=...
datasource.db2.username=...
datasource.db2.password=...
datasource.db2.jdbcUrl=...
Run Code Online (Sandbox Code Playgroud)

2. 定义你的实体(每个数据库一个)

Student.java // 用于 db1

@Table("STUDENT_TABLE")
public class Student{
    @Id
    @Column("MAT_NR")
    private BigDecimal matNr;

    @Column("NAME")
    private String name;
}
Run Code Online (Sandbox Code Playgroud)

Teacher.java // 用于 db2

@Table("TEACHER_TABLE")
public class Teacher{
    @Id
    @Column("EMPLOYEE_NR")
    private BigDecimal employeeNr;

    @Column("NAME")
    private String name;
}
Run Code Online (Sandbox Code Playgroud)

3.定义您的存储库(每个数据库一个)

StudentRepository.java // 用于 DB1

@Repository
public interface StudentRepository extends CrudRepository<Student, BigDecimal> {}
Run Code Online (Sandbox Code Playgroud)

TeacherRepository.java // 用于 DB2

@Repository
public interface TeacherRepository extends CrudRepository<Teacher, BigDecimal> {}
Run Code Online (Sandbox Code Playgroud)

4. 定义你的@Configuration 类(每个数据库一个)

  • 你也可以在一门课上同时参加,但我是这样做的:

数据库配置文件

@Configuration
public class Db1Config {
    @Primary
    @Bean("db1DataSource")
    @ConfigurationProperties("datasource.db1")
    public DataSource db1DataSource() {
        return DataSourceBuilder.create().build();
    }
}
Run Code Online (Sandbox Code Playgroud)

数据库配置文件

@Configuration
public class Db2Config {
    @Bean("db2DataSource")
    @ConfigurationProperties("datasource.db2")
    public DataSource db2DataSource() {
        return DataSourceBuilder.create().build();
    }
}
Run Code Online (Sandbox Code Playgroud)

5. 使用你的接口库

应用程序.java

@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired @Qualifier("studentRepository") StudentRepository studentRepository
    @Autowired @Qualifier("teacherRepository") TeacherRepository teacherRepository 

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

    @Override
    public void run(String... args) throws Exception {
        studentRepository.findById(30688).ifPresent(System.out::println); // DB1
        teacherRepository.findById(5).ifPresent(System.out::println); // DB2
    }
}
Run Code Online (Sandbox Code Playgroud)

这些工作正常!

这里的问题是,它TeacherRepository不是查询 DB2,而是查询 DB1。

这导致错误:[...]: Unknown table name:TEACHER

有谁知道我如何配置 TeacherRepository 使用 DB2 作为数据源?

# 回答前请注意:

这里我使用的是Spring Data JDBC而不是Spring Data JPA。我知道它在Spring Data JPA 中工作,就像这里描述的https://www.baeldung.com/spring-data-jpa-multiple-databases。我也知道我可以使用这些JdbcTemplate。但是那样的话,我必须自己编写这些 CRUD 操作,这在这里描述,这不是必需的。

一个答案当然会很好。

谢谢你的帮助。

Twi*_*kie 5

我有类似的问题。根据 Chris Savory 的回答,我的解决方案必须将我的存储库放入 2 个单独的包中,然后定义 2 个 @Configuration 类,每个类定义 1 个 JdbcOperation。这是我的完整配置(我有一个 SQL Server 和一个 H2 数据源):

应用程序属性

请注意,这些属性是 Hikari CP 特定的。如果您选择不同的 CP(即 Tomcat),里程可能会有所不同

## SQL SERVER DATA SOURCE
spring.sql-server-ds.jdbcUrl= jdbc:sqlserver://localhost:1554;databaseName=TestDB
spring.sql-server-ds.username= uteappl
spring.sql-server-ds.password= mypassword

## H2 DATA SOURCE
spring.h2-ds.jdbcUrl= jdbc:h2:mem:testdb;mode=MySQL
spring.h2-ds.username= sa
spring.h2-ds.password= password
Run Code Online (Sandbox Code Playgroud)

第一个 H2 @Configuration

@Configuration
@EnableJdbcRepositories(jdbcOperationsRef = "h2JdbcOperations", basePackages = "com.twinkie.repository.h2")
public class H2JdbcConfiguration extends AbstractJdbcConfiguration {


  @Bean
  @ConfigurationProperties(prefix = "spring.h2-ds")
  public DataSource h2DataSource() {
    return DataSourceBuilder.create().build();
  }


  @Bean
  NamedParameterJdbcOperations h2JdbcOperations(@Qualifier("h2DataSource") DataSource sqlServerDs) {
    return new NamedParameterJdbcTemplate(sqlServerDs);
  }

  @Bean
  public DataSourceInitializer h2DataSourceInitializer(
      @Qualifier("h2DataSource") final DataSource dataSource) {
    ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator(
        new ClassPathResource("schema.sql"));
    DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
    dataSourceInitializer.setDataSource(dataSource);
    dataSourceInitializer.setDatabasePopulator(resourceDatabasePopulator);
    return dataSourceInitializer;
  }
}
Run Code Online (Sandbox Code Playgroud)

第二个 SQL Server @Configuration

@Configuration
@EnableJdbcRepositories("com.twinkie.repository.sqlserver")
public class SqlServerJdbcConfiguration {

  @Bean
  @Primary
  @ConfigurationProperties(prefix = "spring.sql-server-ds")
  public DataSource sqlServerDataSource() {
    return DataSourceBuilder.create().build();
  }

  @Bean
  @Primary
  NamedParameterJdbcOperations jdbcOperations(
      @Qualifier("sqlServerDataSource") DataSource sqlServerDs) {
    return new NamedParameterJdbcTemplate(sqlServerDs);
  }

}
Run Code Online (Sandbox Code Playgroud)

然后我就有了我的存储库(请注意不同的包)。

SQL服务器

package com.twinkie.repository.sqlserver;

import com.twinkie.model.SoggettoAnag;
import java.util.List;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;

public interface SoggettoAnagRepository extends CrudRepository<SoggettoAnag, Long> {

  @Query("SELECT * FROM LLA_SOGGETTO_ANAG WHERE sys_timestamp > :sysTimestamp ORDER BY sys_timestamp ASC")
  List<SoggettoAnag> findBySysTimestampGreaterThan(Long sysTimestamp);
}
Run Code Online (Sandbox Code Playgroud)

氢2

package com.twinkie.repository.h2;

import com.twinkie.model.GlSync;
import java.util.Optional;
import org.springframework.data.jdbc.repository.query.Modifying;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.Repository;

public interface GlSyncRepository extends Repository<GlSync, String> {

  @Modifying
  @Query("INSERT INTO GL_SYNC (table_name, last_rowversion) VALUES (:tableName, :rowVersion) ON DUPLICATE KEY UPDATE last_rowversion = :rowVersion")
  boolean save(String tableName, Long rowVersion);

  @Query("SELECT table_name, last_rowversion FROM gl_sync WHERE table_name = :tableName")
  Optional<GlSync> findById(String tableName);
}
Run Code Online (Sandbox Code Playgroud)