有了之前的student表,address表后,再加上一张表,grade年级表,一个年级对应多个学生,在查询grade表的时候,一并查询学生表.
一条grade数据对就多条学生数据,一对多关系.
一.首先完成从grade----> student的单向联结.
1.建表mybatis_grade.
package com.skymr.mybatis.model;
import java.util.List;
public class Grade {
private int id;
private String gradeName;
private List<Student> students;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getGradeName() {
return gradeName;
}
public void setGradeName(String gradeName) {
this.gradeName = gradeName;
}
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
public String toString(){
return "["+id+","+gradeName+","+students+"]";
}
}
2.GradeMapper接口
package com.skymr.mybatis.mappers;
import com.skymr.mybatis.model.Grade;
public interface GradeMapper {
public Grade getGrade(int id);
}
3.GradeMapper.xml映射
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.skymr.mybatis.mappers.GradeMapper">
<select id="getGrade" resultMap="gradeMap" parameterType="int">
select * from mybatis_grade where id=#{id}
</select>
<resultMap type="Grade" id="gradeMap">
<id property="id" column="id"/>
<result property="gradeName" column="grade_name"/>
<!-- 根据id查询student getStudentsByGradeId -->
<!-- column传入grade主键 -->
<collection property="students" column="id" select="com.skymr.mybatis.mappers.StudentMapper.getStudentsByGradeId"></collection>
</resultMap>
</mapper>
4.为StudentMapper添加getStudentsByGradeId方法
public List<Student> getStudentsByGradeId(int gradeId);
<select id="getStudentsByGradeId" resultMap="stuMapWithAddr" parameterType="int">
select * from mybatis_Student where grade_id=#{gradeId}
</select>
<resultMap type="Student" id="stuMapWithAddr">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<association property="address" column="address_id" select="com.skymr.mybatis.mappers.AddressMapper.getAddress">
</association>
</resultMap>
5.测试.
package com.skymr.mybatis.service;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.skymr.mybatis.mappers.GradeMapper;
import com.skymr.mybatis.model.Grade;
import com.skymr.mybatis.util.MybatisUtil;
public class GradeTest {
private Logger logger = LoggerFactory.getLogger(GradeTest.class);
private SqlSession session;
@Before
public void beforeTest(){
session = MybatisUtil.openSession();
}
@After
public void afterTest(){
session.close();
}
@Test
public void testGetGrade(){
logger.info("测试取得年级(带学生)");
GradeMapper mapper = session.getMapper(GradeMapper.class);
Grade grade = mapper.getGrade(1);
logger.info(grade.toString());
}
}
二.再完成student--> Grade的单向连接.
这就和上一节学习的差不多了,
1.Student类中加入Grade属性
private Grade grade;
public Grade getGrade() {
return grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
2.StudentMapper.xml修改
<resultMap type="Student" id="stuMapWithAddr">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<association property="address" column="address_id" select="com.skymr.mybatis.mappers.AddressMapper.getAddress">
</association>
<association property="grade" column="grade_id" select="com.skymr.mybatis.mappers.GradeMapper.getGrade"></association>
</resultMap>
3.测试
@Test
public void testGetStudent(){
logger.info("测试取得学生(带地址)");
StudentMapper mapper = session.getMapper(StudentMapper.class);
Student stu= mapper.getStudentWithAddr(1);
logger.info(stu.toString());
ps:student与Grade类的toString 方法要注意,千万不要循环打印了.
想到了一个问题,Student中包含了Grade,Grade又包含了Student,数据库中会不会循环查询呢?
进行验证吧,
(1)把Student类,Grade类的toString 方法去掉
(2)修改测试方法
@Test
public void testGetStudent(){
logger.info("测试取得学生(带地址)");
StudentMapper mapper = session.getMapper(StudentMapper.class);
Student stu= mapper.getStudentWithAddr(1);
logger.info(stu.toString());
logger.info(stu.getGrade().toString());
logger.info(stu.getGrade().getStudents().toString());
logger.info(stu.getGrade().getStudents().get(0).getGrade().toString());
logger.info(stu.getGrade().getStudents().get(0).getGrade().getStudents().toString());
}
打印结果
2015-08-31 12:01:26 564 ->[main]--[INFO ]--[StudentTest3]--测试取得学生(带地址)
2015-08-31 12:01:27 067 ->[main]--[INFO ]--[StudentTest3]--com.skymr.mybatis.model.Student@1bbc3eb
2015-08-31 12:01:27 067 ->[main]--[INFO ]--[StudentTest3]--com.skymr.mybatis.model.Grade@3b8a9a
2015-08-31 12:01:27 067 ->[main]--[INFO ]--[StudentTest3]--[com.skymr.mybatis.model.Student@1089c2c]
2015-08-31 12:01:27 067 ->[main]--[INFO ]--[StudentTest3]--com.skymr.mybatis.model.Grade@3b8a9a
2015-08-31 12:01:27 067 ->[main]--[INFO ]--[StudentTest3]--[com.skymr.mybatis.model.Student@1089c2c]
结果表明,第一行Student实例与第三行实例不等,之后的实例就相互指引了,数据库中没有循环查询.
数据库中查询了3次:
第1次查询student表,
第2次查询Gradent表,
第3次再查询Student表,其实这次是多余的,可以经过配置去掉.
总结:一对多关系与一对一相似,主要的差别是association与connection, association是外键关联主键,一对一,connection是主键关联外键,一对多.