这一篇博客讲述一对多关系映射。以班级学生为例。
在上一个工程的基础上:
1.数据库中新建表t_grade,并添加数据:
把这个表和t_student建立一对多关联:
表t_student中添加字段gradeId:
2.新建类Grade:
package com.test.model;
import java.util.List;
public class Grade {
private Integer id;
private String gradeName;
private List students;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getGradeName() {
return gradeName;
}
public void setGradeName(String gradeName) {
this.gradeName = gradeName;
}
public List getStudents() {
return students;
}
public void setStudents(List students) {
this.students = students;
}
@Override
public String toString() {
return "Grade [id=" + id + ", gradeName=" + gradeName + ", students=" + students + "]";
}
}
2.新建Grade的数据库操作接口GradeMapper:
package com.test.mappers;
import com.test.model.Grade;
public interface GradeMapper {
public Grade findById(Integer id);
}
3.实现这个方法:
这里和一对多类似。定义的结果映射中,通过
这个方法的执行结果赋值给Grade类对象的students属性。
4.这里在StudentMapper中添加通过年级Id查询学生信息的方法:
public Student findByGradeId(Integer gradeId);
5.新建测试类GradeTest:
package com.test.service;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.test.mappers.GradeMapper;
import com.test.model.Grade;
import com.test.util.SqlSessionFactoryUtil;
public class GradeTest {
private static Logger logger = Logger.getLogger(GradeTest.class);
private SqlSession sqlSession = null;
private GradeMapper gradeMapper = null;
@Before
public void setUp() throws Exception {
sqlSession = SqlSessionFactoryUtil.openSession();
gradeMapper = sqlSession.getMapper(GradeMapper.class);
}
@After
public void tearDown() throws Exception {
sqlSession.close();
}
@Test
public void testFindGradeWithStudent() {
logger.info("查询年级(带学生信息)");
Grade grade = gradeMapper.findById(2);
System.out.println(grade);
}
}
[main] INFO com.test.service.GradeTest - 查询年级(带学生信息)
Grade [id=2, gradeName=大二, students=[Student [id=4, name=李四2, age=11, address=Address [id=2, sheng=广西省, shi=南宁市, qu=兴宁区]], Student [id=5, name=王五, age=15, address=Address [id=1, sheng=广西省, shi=南宁市, qu=青秀区]]]]
这里通过年级查询出来这个年级的所有学生信息。
说一下执行过程:
1)运行测试方法,学生id=2传入到GradeMapper.xml中的findById方法中。执行这个方法的sql语句,查询结果为:
2)按照结果映射GradeResult封装返回结果:
2.1)把id列的值付给Grade类对象的id属性,把gradeName列的值付给Grade类对象的gradeName属性。扫描到
2.2)执行findByGradeId方法的sql语句,得到查询结果:
按照结果映射StudentResult封装返回结果:还会到t_address中查询出学生的地址信息(这个过程在一对一关系映射中
讲过),这里就不再讲述过程了。
3)得到带有学生的年级结果后打印出年级信息。
以上就实现了查询年级信息的时候查询出年级的所有学生信息。
进一步的讲,在查询学生信息的时候,我们也希望能够查询出学生所在的班级信息。为此进行如下修改:
1.在Student类中添加属性grade:
生成这个属性的get和set方法,并重新Student类的toString方法。
2.修改StudentMapper.xml中的结果映射StudentResult为:
3.StudentTest3类中新建测试方法:
@Test
public void testFindStudentWithGrade() {
logger.info("查询学生(带年级)");
Student student = studentMapper.findStudentWithAddress(2);
System.out.println(student);
}
运行这个测试方法:
程序报错了,报错为栈溢出。出现这个问题的原因是程序陷入了死循环。这个方法中有打印学生信息,
Student类的toString方法中显示在打印学生信息的时候会打印学生所在的班级信息。Grade类的toString方法显示打印
班级信息的时候会打印班级中的学生信息。这样就陷入了打印死循环。
为了解决这个问题,修改一下Grade类的toString方法:
@Override
public String toString() {
return "Grade [id=" + id + ", gradeName=" + gradeName + "]";
}
运行上述测试方法,控制台输出为:
[main] INFO com.test.service.StudentTest - 查询学生(带年级)
Student [id=2, name=李四, age=11, address=Address [id=2, sheng=广西省, shi=南宁市, qu=兴宁区], grade=Grade [id=1, gradeName=大一]]