引子:
写代码中,如果在for中有查询数据的,一般大多数公司,都要求批量查询,或者说不让在for中查询太多的数据库。今天简单说一下
1.需求:
学生和科目。学生和科目是一对的关系。现在要求查询出全班学生的所有科目的成绩。
实体:
student :学生实体
subject:科目实体
<code>public class Student {
private Long id;
private String name;
private Integer age;
private Integer sex;
private List<subject> subjectList;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public List<subject> getSubjectList() {
return subjectList;
}
public void setSubjectList(List<subject> subjectList) {
this.subjectList = subjectList;
}
}
public class Subject {
private Long id;
private Long studentId;
private String name;
private Float age;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getStudentId() {
return studentId;
}
public void setStudentId(Long studentId) {
this.studentId = studentId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getAge() {
return age;
}
public void setAge(Float age) {
this.age = age;
}
}/<subject>/<subject>/<subject>/<code>
<code>/** * 查询学生信息 * @param studentIds * @return */
private List<student> queryStudent(List<long> studentIds) {
// 查询数据库
return new ArrayList<>();
}
/** * 查询科目信息 * @param subjectIds * @return */
private List<subject> querySubject(List<long> subjectIds) {
// 查询数据库
return Lists.newArrayList();
}
/** * 查询科目信息 * @param subjectId * @return */
private List<subject> querySubject(Long subjectId) {
// 查询数据库
return Lists.newArrayList();
}/<subject>/<long>/<subject>/<long>/<student>/<code>
2.不同方案
2.1单次查询:
<code>/** * 单次查询 * @param ids * @return */
private List<student> queryStudentAndSubject(List<long> ids){
List<student> students = queryStudent(ids);
students.forEach(student->{
List<subject> subjects = querySubject(student.id);
student.setSubjectList(subjects);
});
return students;
}/<subject>/<student>/<long>/<student>/<code>
2.2批量查询:
<code>/** * 批量查询 * @param ids * @return */private List<student> queryBatchStudentAndSubject(List<long> ids){
List<student> students = queryStudent(ids);
List<subject> subjects = querySubject(ids);
Map<long>> studentMap=new HashMap<>();
subjects.forEach(subject -> {
Long studentId = subject.getStudentId();
List<subject> subjectsList = studentMap.get(studentMap);
if(CollectionUtils.isEmpty(subjectsList)){
subjectsList=new ArrayList<>();
studentMap.put(studentId,subjectsList);
}
subjectsList.add(subject);
});
students.forEach(student->{
List<subject> subjects1 = studentMap.get(student.getId());
student.setSubjectList(subjects1);
});
return students;
}/<subject>/<subject>/<long>/<subject>/<student>/<long>/<student>/<code>
2.3批量查询:使用Guava写法1
<code>/** * 批量查询 * @param ids * @return */
private List<student> queryBatchStudentAndSubject2(List<long> ids){
List<student> students = queryStudent(ids);
List<subject> subjects = querySubject(ids);
ArrayListMultimap<long> map=new ArrayListMultimap<>();
subjects.forEach(subject -> {
map.put(subject.getStudentId(),subject);
});
students.forEach(student->{
List<subject> subjectList = map.get(student.getId());
student.setSubjectList(subjectList);
});
return students;
}/<subject>/<long>/<subject>/<student>/<long>/<student>/<code>
2.4批量查询:使用Guava写法2
<code>/** * 批量查询 * @param ids * @return */
private List<student> queryBatchStudentAndSubject3(List<long> ids){
List<student> students = queryStudent(ids);
List<subject> subjects = querySubject(ids);
Map<long>> map = Multimaps.index(subjects, Subject::getStudentId).asMap();
students.forEach(student->{
Collection<subject> subjectsList = map.get(student.getId());
student.setSubjectList(new ArrayList<>(subjectsList));
});
return students;
}/<subject>/<long>/<subject>/<student>/<long>/<student>/<code>
2.5对比
2.1和2.2
<code>ArrayListMultimap<long> map=new ArrayListMultimap<>();
subjects.forEach(subject -> {
map.put(subject.getStudentId(),subject);
});
students.forEach(student->{
List<subject> subjectList = map.get(student.getId());
student.setSubjectList(subjectList);
});/<subject>/<long>/<code>
<code>Map<long>> studentMap=new HashMap<>();
subjects.forEach(subject -> {
Long studentId = subject.getStudentId();
List<subject> subjectsList = studentMap.get(studentMap);
if(CollectionUtils.isEmpty(subjectsList)){
subjectsList=new ArrayList<>();
studentMap.put(studentId,subjectsList);
}
subjectsList.add(subject);
});/<subject>/<long>/<code>
2.1和2.3
<code>Map<long>> map = Multimaps.index(subjects, Subject::getStudentId).asMap();
students.forEach(student->{
Collection<subject> subjectsList = map.get(student.getId());
student.setSubjectList(new ArrayList<>(subjectsList));
});/<subject>/<long>/<code>
<code>Map<long>> studentMap=new HashMap<>();
subjects.forEach(subject -> {
Long studentId = subject.getStudentId();
List<subject> subjectsList = studentMap.get(studentMap);
if(CollectionUtils.isEmpty(subjectsList)){
subjectsList=new ArrayList<>();
studentMap.put(studentId,subjectsList);
}
subjectsList.add(subject);
});
students.forEach(student->{
List<subject> subjects1 = studentMap.get(student.getId());
student.setSubjectList(subjects1);
});/<subject>/<subject>/<long>/<code>
可以看出代码越来越精简。
这就是为什么强烈推荐Java程序员使用Google Guava编程。
上面只是其中的点点。Guava还有其他优雅的写法。以后再说。
http://code.google.com/p/guava-libraries/wiki/GuavaExplained
最后附上Multimap提供了丰富的实现(从网上找了一个图)