spring - 使用 Spring Data JDBC 和 CrudRepository 接口(interface)的多个数据源

标签 spring spring-boot spring-data-jdbc

我有一个不简单的问题:

我的情况:

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

  • 如您所见here在 Spring Data JDBC 中,您可以 extends CrudRepository并使用 Spring 开箱即用所有 Crud 操作 - 无需显式实现!

    这是一个简单的 4 步过程:
  • 定义您的属性
  • 定义您的实体
  • 定义一个扩展 CrudRepository 和
  • 的接口(interface)
  • 使用该接口(interface)

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

    我做了这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>
    

    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=...
    

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

    学生.java //对于 db1
    @Table("STUDENT_TABLE")
    public class Student{
        @Id
        @Column("MAT_NR")
        private BigDecimal matNr;
    
        @Column("NAME")
        private String name;
    }
    

    教师.java //对于 db2
    @Table("TEACHER_TABLE")
    public class Teacher{
        @Id
        @Column("EMPLOYEE_NR")
        private BigDecimal employeeNr;
    
        @Column("NAME")
        private String name;
    }
    

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

    StudentRepository.java //对于 DB1
    @Repository
    public interface StudentRepository extends CrudRepository<Student, BigDecimal> {}
    

    TeacherRepository.java //对于 DB2
    @Repository
    public interface TeacherRepository extends CrudRepository<Teacher, BigDecimal> {}
    

    4. 定义您的@Configuration 类(每个数据库一个)
  • 你也可以在一个类上两门课,但我是这样做的:

  • Db1Config.java
    @Configuration
    public class Db1Config {
        @Primary
        @Bean("db1DataSource")
        @ConfigurationProperties("datasource.db1")
        public DataSource db1DataSource() {
            return DataSourceBuilder.create().build();
        }
    }
    

    Db2Config.java
    @Configuration
    public class Db2Config {
        @Bean("db2DataSource")
        @ConfigurationProperties("datasource.db2")
        public DataSource db2DataSource() {
            return DataSourceBuilder.create().build();
        }
    }
    

    5.利用你的接口(interface)存储库

    应用程序.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
        }
    }
    

    这些工作正常!

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

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

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

    # 回答前请注意:

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

    一个答案当然会很好。

    谢谢你的帮助。

    最佳答案

    我有一个类似的问题。根据 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
    

    第一个 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;
      }
    }
    

    第二个 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);
      }
    
    }
    

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

    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);
    }
    

    H2
    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);
    }
    

    关于spring - 使用 Spring Data JDBC 和 CrudRepository 接口(interface)的多个数据源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58960333/

    相关文章:

    java - 使用 Selenium WebDriver 的 Spring Boot Web 应用程序

    java - 我是否需要为我的 Spring Data JDBC 项目配置以下示例中的 bean?

    java - spring boot 2.3.0.RELEASE : UnsatisfiedDependencyException for Oracle 12. 2.0.1 jdbcdriver中的新错误,但不是mysql jdbcdriver

    postgresql - 不接受嵌入对象的空值

    spring - 用 Thymeleaf 扩展视野

    java - Hibernate HQL Count Distinct 不起作用?

    java - 在 Spring Security 获得机会之前创建一个处理请求的 Vaadin 请求处理程序

    java - Hibernate遇到mysql异常:= operator

    Spring security与Hibernate,存储加密密码

    mysql - 使用 CrudRepository 删除带有集合的实体时,Hibernate-envers 抛出异常