我应该如何编写RowMapper与其他Object依赖项?

时间:2016-02-22 11:41:57

标签: java mysql spring jdbc dao

简介

这是交易,让我们假设我的豆子是这样的:

public class Bean1 {
    private long id;
    private long idBean2;
    private Bean2 bean2;
}

public class Bean2 {
    private long id;
}

(假设对应的getter和setter)

我想从我的数据库中检索一个非常大数量的Bean1与关联的DAO,我希望它与Bean2相关联。我该怎么办?我有三个想法,都有利有弊,我应该选择哪一个?

(假设自动连接,服务,JDBC初始化)

创意1

public class Bean1Dao {
    public List<Bean1> selectBean1s() {
        String query =
            "SELECT " +
            "  b1.* " +
            "  b2.* " +
            "FROM " +
            "  BEAN1 b1 " +
            "  INNER JOIN BEAN2 b2 ON b1.ID_B2 = b2.ID";

        return jdbcTemplate.query(query, new Bean1Mapper());
    }

    public static class Bean1Mapper implements ParameterizedRowMapper<Bean1> {
        @Override
        public Bean1 mapRow(final ResultSet rs, final int rownum) throws SQLException {
            Bean1 bean1 = new Bean1();
            bean1.setId = rs.getLong("b1.ID");
            bean1.setIdBean2 = rs.getLong("b1.ID_B2");
            try {
                bean1.setBean2 = new Bean2Dao.Bean2Mapper().mapRow(rs, rownum);
            } catch (Exception e) {
                // Log exception here... Or not
            }
        }
    }
}

public class Bean2Dao {
    public List<Bean2> selectBean2s() {
        String query = "SELECT b2.* FROM BEAN2";
        return jdbcTemplate.query(query, new Bean2Mapper());
    }

    public static class Bean2Mapper implements ParameterizedRowMapper<Bean2> {
        @Override
        public Bean2 mapRow(final ResultSet rs, final int rownum) throws SQLException {
            Bean2 bean2 = new Bean2();
            bean2.setId = rs.getLong("b2.ID");
        }
    }
}

优点:1 SQL查询

缺点:需要在所有看起来很重的SQL查询中指定前缀,并且(我很确定)会因缺少前缀而导致恼人的错误。

创意2

public class Bean1Dao {
    public List<Bean1> selectBean1s() {
        String query = "SELECT * FROM BEAN1";
        return jdbcTemplate.query(query, new Bean1Mapper());
    }

    public static class Bean1Mapper implements ParameterizedRowMapper<Bean1> {
        @Override
        public Bean1 mapRow(final ResultSet rs, final int rownum) throws SQLException {
            Bean1 bean1 = new Bean1();
            bean1.setId = rs.getLong("ID");
            bean1.setIdBean2 = rs.getLong("ID_B2");
        }
    }
}

在这种情况下,DAO不映射Bean2对象,服务必须遍历Bean1对象并为每个对象调用Bean2Dao,以便使用idBean2属性映射它。

优点:非常简单且外观轻巧的查询

缺点:执行速度很慢(我在这里谈论的是数千或者数百万个对象,在这种情况下意味着相同数量的数据库调用)

创意3

public class Bean1Dao {
    public Map<Long, Bean1> selectBean1Map() {
        String query = "SELECT * FROM BEAN1";
        List<Bean1> bean1List = jdbcTemplate.query(query, new Bean1Mapper());

        Map<Long, Bean1> bean1Map = new HashMap<Long, Bean1>();
        for (Bean1 bean1 : bean1List) {
            bean1Map.put(bean1.getId(), bean1);
        }
        return bean1Map;
    }

    public static class Bean1Mapper implements ParameterizedRowMapper<Bean1> {
        @Override
        public Bean1 mapRow(final ResultSet rs, final int rownum) throws SQLException {
            Bean1 bean1 = new Bean1();
            bean1.setId = rs.getLong("ID");
            bean1.setIdBean2 = rs.getLong("ID_B2");
        }
    }
}

public class Bean2Dao {
    public Map<Long, Bean2> selectBean2Map() {
        String query = "SELECT * FROM BEAN2";
        List<Bean2> bean2List = jdbcTemplate.query(query, new Bean2Mapper());

        Map<Long, Bean2> bean2Map = new HashMap<Long, Bean2>();
        for (Bean2 bean2 : bean2List) {
            bean2Map.put(bean2.getId(), bean2);
        }
        return bean2Map;
    }

    public static class Bean2Mapper implements ParameterizedRowMapper<Bean2> {
        @Override
        public Bean2 mapRow(final ResultSet rs, final int rownum) throws SQLException {
            Bean2 bean2 = new Bean2();
            bean2.setId = rs.getLong("ID");
        }
    }
}

这里服务需要循环遍历bean1Map以从bean2Map分配对象。

优点:n查询和轻量级的DAO(n指向要在数据库中查找的Bean1成员的数量(此处n = 1,但在我的情况下它更大))

缺点:n个查询(构思1只有1个查询)

结论

我不太确定采用哪种解决方案。也许我错过了另一个更好的解决方案,或者可能有一个我缺少的标准,它定义了应该如何完成的事情。 我非常感谢你提出任何意见。

TL; DR:在非常大数据量的情况下,如何从数据库中检索对象并链接其同样位于数据库中的成员?

2 个答案:

答案 0 :(得分:1)

你是否绝对需要在你的记忆中的所有豆类在一个时间点?

我的建议:选择 1 选项 - 即使您必须为自己的内容添加前缀。

Con:编写SQL代码的时间(一次性)

<强>临

  • 效果:您声称自己拥有非常多的行。说1.000.000行。考虑1.000.000额外SQL往返的成本(这些包括Network-I / O,因此以毫秒为单位)。您可以轻松地将数千秒(又名数小时)的执行时间添加到您的代码中。
  • 内存占用:所有bean对象。无法帮助。

选项 3 看起来也很有前景 - 但是您在地图中添加了1.000.000个额外的查找以及额外的SQL语句到您的代码中。

顺便说一句:如果你把bean1Map.put(bean1.getIdBean2(), bean1);放在bean2循环中,你只需要一个地图找到匹配的bean1并设置bean2 ...

答案 1 :(得分:0)

您没有说目标是内存效率,快速执行还是最少编程。如果你正在寻找内存效率,我会使用选项1。

您可以通过使用多个线程来改善任何方法的执行时间。每个线程都需要选择要处理的行的子集。

如果您愿意使用其他图书馆,我建议您撰写sormula。您可以使用ScalarSelectOperationSelectIterator一次读取一个Bean1。 Sormula将执行Bean2的级联选择。 Sormula将只使用2个准备好的JDBC语句,一个用于Bean1表,一个用于Bean2表。