Spring Data JPA 将存储过程结果从多个数据源映射到非实体 POJO

Spring Data JPA map the stored procedure result to Non-Entity POJO from multiple data source

我曾尝试研究一种更好的方法来调用两个不同数据源上的两个存储过程,但没有成功。这是我的场景,我连接到两个数据源,每个数据源都有一个存储过程。每当我将一个配置注释为主要配置时,我都会得到结果,另一个未映射为主要配置的配置会抛出错误

The given SqlResultSetMapping name [Unknown SqlResultSetMapping [Testing]] is unknown

当我将调用存储过程的 class 的其他配置设置为主要时,它显示了结果,但是当它们都没有设置为主要时,它们会抛出错误

The given SqlResultSetMapping name [Unknown SqlResultSetMapping [Testing]] is unknown

卡了好几天了。我会提前感谢你help.Thank

我调用第一个数据源的第一个配置

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "guru.springframework.multipledatasources.model.Card",
        entityManagerFactoryRef = "cardEntityManagerFactory",
        transactionManagerRef= "cardTransactionManager")
public class Cardonfiguration {

        @Bean
        @Primary
        @ConfigurationProperties("datasource.card")
        public DataSourceProperties cardDataSourceProperties() {
            return new DataSourceProperties();
        }

        @Bean
        @Primary
        @ConfigurationProperties("datasource.card.configuration")
        public DataSource cardDataSource() {
            return cardDataSourceProperties().initializeDataSourceBuilder()
                    .type(BasicDataSource.class).build();
        }

        @Primary
        @Bean(name = "cardEntityManagerFactory")
        public LocalContainerEntityManagerFactoryBean cardEntityManagerFactory(
                EntityManagerFactoryBuilder builder) {
            return builder
                    .dataSource(cardDataSource())
                    .packages(Card.class)
                    .build();
        }

        @Primary
        @Bean
        public PlatformTransactionManager cardTransactionManager(
                final @Qualifier("cardEntityManagerFactory") LocalContainerEntityManagerFactoryBean cardEntityManagerFactory) {
            return new JpaTransactionManager(Objects.requireNonNull(cardEntityManagerFactory.getObject()));
    }
}

第二个数据源的第二个配置

@Configuration
@EnableJpaRepositories(basePackages = "guru.springframework.multipledatasources.model.member",
        entityManagerFactoryRef = "memberEntityManagerFactory",
        transactionManagerRef= "memberTransactionManager")
public class MemberConfiguration {
    @Bean
    @ConfigurationProperties("datasource.member")
    public DataSourceProperties zamphiaDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @ConfigurationProperties("datasource.member.configuration")
    public DataSource memberDataSource() {
        return memberDataSourceProperties().initializeDataSourceBuilder()
                .type(BasicDataSource.class).build();
    }

    @Bean(name = "memberEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean memberEntityManagerFactory(
            EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(memberDataSource())
                .packages(member.class)
                .build();
    }

    @Bean
    public PlatformTransactionManager memberTransactionManager(
            final @Qualifier("memberEntityManagerFactory") LocalContainerEntityManagerFactoryBean memberEntityManagerFactory) {
        return new JpaTransactionManager(memberEntityManagerFactory.getObject());
    }

}

我的第一个数据源控制器

@RequestMapping("/api/v1")
@RestController
public class CardReports {

    @PersistenceContext
    private EntityManager entityManager;

    @SuppressWarnings("unchecked")
    @RequestMapping("/reports/CARD/dailyreport")
    public List<Testing> getDailyAchievements(){
        List<Testing> list;
        StoredProcedureQuery query = entityManager.createStoredProcedureQuery("dailyreports", "Testing");
        try {
            // Execute query
            query.execute();
            list = query.getResultList();
        } finally {
            try {
                query.unwrap(ProcedureOutputs.class).release();
            } catch (Exception e) {
            }
        }
        return list;
    }
}

第一个数据源的非实体

@MappedSuperclass
@SqlResultSetMapping(name = "Testing", classes = @ConstructorResult(targetClass = Testing.class, columns = {
        @ColumnResult(name = "TTEAM_ID", type = Integer.class),
        @ColumnResult(name = "VDATE", type = String.class),
        @ColumnResult(name="Days_in_Field", type = String.class),
        @ColumnResult(name= "Expected_cummilative_Number_of_HH", type = String.class),
        @ColumnResult(name="Cummlative_HH_Reached", type = String.class),
        @ColumnResult(name="HH_Reached_for_day", type = String.class),
        @ColumnResult(name ="HHs_Finalised_for_day", type = String.class),
        @ColumnResult(name="Number_of_HH_in_process_for_day", type = String.class),
        @ColumnResult(name="Number_of_HH_Refused_for_day", type = String.class),
        @ColumnResult(name="Number_of_Revisits_Scheduled_for_day", type = String.class),
        @ColumnResult(name="HH_loss_3rd_visit_attempt_refusals_for_day", type = String.class)
}))

public class Testing {
    private Integer TTEAM_ID;
    private String  VDATE;
    private String Days_in_Field;
    private String Expected_cummilative_Number_of_HH;
    private String Cummlative_HH_Reached;
    private String HH_Reached_for_day;
    private String HHs_Finalised_for_day;
    private String Number_of_HH_in_process_for_day;
    private String Number_of_HH_Refused_for_day;
    private String Number_of_Revisits_Scheduled_for_day;
    private String HH_loss_3rd_visit_attempt_refusals_for_day;

    public Testing(Integer TTEAM_ID, String VDATE, String Days_in_Field, String Expected_cummilative_Number_of_HH, String Cummlative_HH_Reached, String HH_Reached_for_day, String HHs_Finalised_for_day, String Number_of_HH_in_process_for_day, String Number_of_HH_Refused_for_day, String Number_of_Revisits_Scheduled_for_day, String HH_loss_3rd_visit_attempt_refusals_for_day) {
        this.TTEAM_ID = TTEAM_ID;
        this.VDATE = VDATE;
        this.Days_in_Field = Days_in_Field;
        this.Expected_cummilative_Number_of_HH = Expected_cummilative_Number_of_HH;
        this.Cummlative_HH_Reached = Cummlative_HH_Reached;
        this.HH_Reached_for_day = HH_Reached_for_day;
        this.HHs_Finalised_for_day = HHs_Finalised_for_day;
        this.Number_of_HH_in_process_for_day= Number_of_HH_in_process_for_day;
        this.Number_of_HH_Refused_for_day = Number_of_HH_Refused_for_day;
        this.Number_of_Revisits_Scheduled_for_day = Number_of_Revisits_Scheduled_for_day;
        this.HH_loss_3rd_visit_attempt_refusals_for_day = HH_loss_3rd_visit_attempt_refusals_for_day;
    }
//getters and setters

我的第二个数据源控制器

 @RequestMapping("/api/v1")
    @RestController
    public class MemberDaily {
    
        @PersistenceContext
        private EntityManager entityManager;
    
        @SuppressWarnings("unchecked")
        @RequestMapping("/reports/member/dailyachievementreport")
        public List<DailyReport> getDailyAchievements(){
            List list;
            StoredProcedureQuery query = entityManager.createStoredProcedureQuery("dailyreports", "Testing");
            try {
                // Execute query
                query.execute();
                list = query.getResultList();
            } finally {
                try {
                    query.unwrap(ProcedureOutputs.class).release();
                } catch (Exception e) {
                }
            }
            return list;
        }
    }

我如何在我的 pojo 上为我的第二个数据源映射结果

@MappedSuperclass
    @SqlResultSetMapping(name = "Testing", classes = @ConstructorResult(targetClass = Testing.class, columns = {
            @ColumnResult(name = "TTEAM_ID", type = Integer.class),
            @ColumnResult(name = "VDATE", type = String.class),
            @ColumnResult(name="Days_in_Field", type = String.class),
            @ColumnResult(name= "Expected_cummilative_Number_of_HH", type = String.class),
            @ColumnResult(name="Cummlative_HH_Reached", type = String.class),
            @ColumnResult(name="HH_Reached_for_day", type = String.class),
            @ColumnResult(name ="HHs_Finalised_for_day", type = String.class),
            @ColumnResult(name="Number_of_HH_in_process_for_day", type = String.class),
            @ColumnResult(name="Number_of_HH_Refused_for_day", type = String.class),
            @ColumnResult(name="Number_of_Revisits_Scheduled_for_day", type = String.class),
            @ColumnResult(name="HH_loss_3rd_visit_attempt_refusals_for_day", type = String.class)
    }))
    
    public class Testing {
        private Integer TTEAM_ID;
        private String  VDATE;
        private String Days_in_Field;
        private String Expected_cummilative_Number_of_HH;
        private String Cummlative_HH_Reached;
        private String HH_Reached_for_day;
        private String HHs_Finalised_for_day;
        private String Number_of_HH_in_process_for_day;
        private String Number_of_HH_Refused_for_day;
        private String Number_of_Revisits_Scheduled_for_day;
        private String HH_loss_3rd_visit_attempt_refusals_for_day;
    
        public Testing(Integer TTEAM_ID, String VDATE, String Days_in_Field, String Expected_cummilative_Number_of_HH, String Cummlative_HH_Reached, String HH_Reached_for_day, String HHs_Finalised_for_day, String Number_of_HH_in_process_for_day, String Number_of_HH_Refused_for_day, String Number_of_Revisits_Scheduled_for_day, String HH_loss_3rd_visit_attempt_refusals_for_day) {
            this.TTEAM_ID = TTEAM_ID;
            this.VDATE = VDATE;
            this.Days_in_Field = Days_in_Field;
            this.Expected_cummilative_Number_of_HH = Expected_cummilative_Number_of_HH;
            this.Cummlative_HH_Reached = Cummlative_HH_Reached;
            this.HH_Reached_for_day = HH_Reached_for_day;
            this.HHs_Finalised_for_day = HHs_Finalised_for_day;
            this.Number_of_HH_in_process_for_day= Number_of_HH_in_process_for_day;
            this.Number_of_HH_Refused_for_day = Number_of_HH_Refused_for_day;
            this.Number_of_Revisits_Scheduled_for_day = Number_of_Revisits_Scheduled_for_day;
            this.HH_loss_3rd_visit_attempt_refusals_for_day = HH_loss_3rd_visit_attempt_refusals_for_day;
        }
    //getters and setters

我认为 SqlResultSetMapping 不适用于 @MappedSuperclass。尝试将其放在实体上。

您的 cardEntityManagerFactory 将扫描 Card.class 的包以查找带有 @ManagedSuperClass 注释的 类 和 memberEntityManagerFactory 将扫描 member.class

的包裹

您似乎在两个控制器中使用相同的 POJO SQLResultSetMapping“测试”。但是不清楚这个POJO在哪个包中。因此,请确保您的 POJO 包已被两个实体管理器扫描。

此外,您只是简单地自动连接实体管理器,而无需在两个控制器中指定名称。据我了解,如果您不指定 Qualifier.

,则只有主实体管理器会在两个控制器中自动装配

我认为,您可以分别在 CardReportsMemberDaily 控制器中尝试使用 @PersistenceContext(name = "cardEntityManagerFactory")@PersistenceContext(name = "memberEntityManagerFactory")

更新

我查看了您的 GitHub 代码,发现您的 BAISVReports 控制器仅获取主实体管理器。因此,只需使用 @Qualifier 自动装配实体管理器,如下所示,现在辅助实体管理器正在自动装配。现在两个控制器都能找到 SQLResultSetMapping

@RequestMapping("/api/v1")
@RestController
public class BAISVReports {

@Autowired
@Qualifier("baisvEntityManagerFactory")
private EntityManager entityManager;

有关详细信息,请参阅 article on How to Configure Multiple Data Sources, Entity Managers, Transaction Managers in Spring Boot