【问题标题】:Spring Data JPA map the stored procedure result to Non-Entity POJO from multiple data sourceSpring Data JPA 将存储过程结果从多个数据源映射到非实体 POJO
【发布时间】:2020-12-04 03:36:28
【问题描述】:

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

给定的 SqlResultSetMapping 名称 [Unknown SqlResultSetMapping [测试]]未知

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

给定的 SqlResultSetMapping 名称 [Unknown SqlResultSetMapping [测试]]未知

卡了好几天了。我将不胜感激。在此先感谢您

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

@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

【问题讨论】:

    标签: java spring-boot hibernate jpa multiple-databases


    【解决方案1】:

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

    看起来您在两个控制器中都使用带有SQLResultSetMapping“Testing”的相同POJO。但不清楚这个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

    【讨论】:

    • 我按照建议做了,但我最终得到错误共享代码link
    • 如何在两个控制器中指定Qualifier
    【解决方案2】:

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

    【讨论】:

    猜你喜欢
    • 2015-05-18
    • 2020-09-21
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 2018-11-25
    • 2017-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多