Spring JDBC中的多个一对多关系

Posted

技术标签:

【中文标题】Spring JDBC中的多个一对多关系【英文标题】:Multiple one-to-many relations in Spring JDBC 【发布时间】:2013-03-07 19:32:31 【问题描述】:

我正在使用 Spring JDBC,我有点不确定如何处理多个一对多关系(或多对多)。在这种情况下,我将一个存储库注入到我的一个结果提取器中,以便我可以检索它的关联。这是这样做的方法吗?不好吗?还有其他更好的方法吗?

注意:我省略了存储库的注入

public class SomeResultSetExtractor implements ResultSetExtractor 

  public Object extractData(ResultSet rs) throws SQLException, DataAccessException 
    List result = new LinkedList();

    while (rs.next()) 
        SomeObject object = new SomeObject(rs.getString(1), rs.getLong(2));
        result.add(object);

        List<AnotherObject> otherObjects = anotherRepository.findAllById(object.getId);
        object.setOtherObjects(otherObjects);
        // and so on
    

    return result;

  

Okey,所以在阅读 Dmytro Polivenok 答案后,我改为改为 RowMapper 界面,我目前正在使用其他存储库来填充所有关联,就像我在示例中显示的那样。这是一个好方法吗?

【问题讨论】:

存储库是否开始新的 SQL 查询? 【参考方案1】:

我认为你的代码可以工作,但这里关注的是 ResultSetExtractor 的使用,它主要用于 JDBC 框架本身,并且在大多数情况下documentation 建议使用 RowMapper。

因此,另一种方法是在您的 DAO 中使用方法来选择和映射父对象。然后为每个对象调用其他存储库或选择和映射子对象的私有方法,然后根据您的关系类型(单向或双向)将子对象与父对象链接。这种方法还可以让您控制是否要加载子对象。

例如,您可以查看具有SimpleJdbcClinic class 的 Spring PetClinic 应用程序

如果你可以使用其他框架,你可以考虑mybatis,它更多的是关于映射并且允许你控制你的SQL代码。

【讨论】:

您好,我不确定我是否正确理解您的回答。假设您有以下课程:电影、演员、流派和评论。你想返回一个包含所有关联的电影对象:一部电影有很多演员、很多 cmets 和一种类型。你会怎么做? 您可以拥有 getMovies 方法,该方法将对电影和流派执行选择,并将它们映射到对象。然后,对于每部电影,使用 select/map 为 actor 调用 Repository,使用 select/map 为 cmets 调用 Repository(或者如果 actor 和 cmets 在您的上下文中仅存在于电影中,那么您可以在私有方法中执行此操作)。在此之后将 cmets 和 authors 设置为电影对象 Okey,所以如果我更改为 rowmapper 界面会更好。但是,您如何处理多对多的情况?映射它们的最佳方法是什么?假设每部电影有很多演员,每个演员都属于很多电影。然后你有一个连接表?您是否在例如名为 findAllActorsForMovie 的演员存储库中创建了一个方法,该方法使用连接表和演员表来创建结果?就像在一对多中一样? 我认为在 Spring JDBC 中没有标准的方法可以做到这一点,因为它提供了执行 SQL 和映射的接口。在多对多的情况下,您需要选择所有关联,映射结果并设置对象。为每个关系建立单独的存储库的决定应基于关系聚合与组合的类型 - 在您的上下文中,演员是否可以在没有电影的情况下存在。因此,如果我们的任务只是加载带有演员的电影,我会在 loadMovies 方法中执行此操作 - 执行所有选择、映射和设置电影到每个演员和演员到每部电影【参考方案2】:

我认为 Spring JDBC 和 SQL 查询的一个好的做法是对每个实体使用一个查询。

例如假设这个模型:

客户(客户 ID、姓名、年龄……) 地址(customerId、类型、街道、城市……)

PaymentOption(客户 ID、卡号、卡类型……)

客户 1---* 地址

客户 1---* PaymentOption

我会构建 3 个查询、3 个 Daos、3 个 ResultSetExtractors/RowcallbackHandlers:

带有 readCustomerData(客户或列表)的 CustomerDao AddressDao 与 readAddressForCustomer(客户或列表) PaymentOptionDao 与 readPaymentOptionsForCustomer(客户或列表)

如果您要在 1 个查询中完成此操作,则必须构建一些逻辑来还原笛卡尔积。

即如果客户有 3 个地址和 2 个付款选项,则查询将返回 6 行。 如果 Address 或 PaymentOption 没有自己的主键,这将变得相当困难。

对于多对多:

客户 * --recommends-- * 产品

我可能会建造:

CustomerDao.readRecommendationsAndProductKeys getDistinctListOfProductKeysFromRecommendations ProductDao.readProducts replaceProductKeysByProductsOnRecommendations

像这样你可以重用 ProductDao.readProducts

客户 * --buys-- * 产品或 ProductGroup 1---* 产品

【讨论】:

谢谢,这和我最后做的差不多。 这不是因为您要多次往返数据库而效率低下吗?假设您有一个具有 3 个集合的对象(一对多关系)如果您需要所有数据,则查询返回 100 个对象,您将依次发出 300 个以上查询以获取完整数据,总共 301 个查询跨度> 这个想法是批处理每个查询。您可以使用 100 个客户 ID 调用 readCustomerData,并根据客户 ID 拆分结果。因此,对于 100 个客户,您仍然只需要 3 个查询。

以上是关于Spring JDBC中的多个一对多关系的主要内容,如果未能解决你的问题,请参考以下文章

如何用jdbc实现一对多

spring+Hibernate 一对多计数行

Spring Boot REST Api中的一对多关系

如何与 Spring 和 thymeleaf 创建一对多的关系?

没有关系的房间中的一对多关系

Hibernate关联关系配置(一对多一对一和多对多)