这是交易,让我们假设我的豆子是这样的:
public class Bean1 {
private long id;
private long idBean2;
private Bean2 bean2;
}
public class Bean2 {
private long id;
}
(假设对应的getter和setter)
我想从我的数据库中检索一个非常大数量的Bean1与关联的DAO,我希望它与Bean2相关联。我该怎么办?我有三个想法,都有利有弊,我应该选择哪一个?
(假设自动连接,服务,JDBC初始化)
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查询中指定前缀,并且(我很确定)会因缺少前缀而导致恼人的错误。
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属性映射它。
优点:非常简单且外观轻巧的查询
缺点:执行速度很慢(我在这里谈论的是数千或者数百万个对象,在这种情况下意味着相同数量的数据库调用)
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:在非常大数据量的情况下,如何从数据库中检索对象并链接其同样位于数据库中的成员?
答案 0 :(得分:1)
你是否绝对需要在你的记忆中的所有豆类在一个时间点?
我的建议:选择 1 选项 - 即使您必须为自己的内容添加前缀。
Con:编写SQL代码的时间(一次性)
<强>临强>
选项 3 看起来也很有前景 - 但是您在地图中添加了1.000.000个额外的查找以及额外的SQL语句到您的代码中。
顺便说一句:如果你把bean1Map.put(bean1.getIdBean2(), bean1);
放在bean2循环中,你只需要一个地图找到匹配的bean1
并设置bean2
...
答案 1 :(得分:0)
您没有说目标是内存效率,快速执行还是最少编程。如果你正在寻找内存效率,我会使用选项1。
您可以通过使用多个线程来改善任何方法的执行时间。每个线程都需要选择要处理的行的子集。
如果您愿意使用其他图书馆,我建议您撰写sormula。您可以使用ScalarSelectOperation或SelectIterator一次读取一个Bean1。 Sormula将执行Bean2的级联选择。 Sormula将只使用2个准备好的JDBC语句,一个用于Bean1表,一个用于Bean2表。