写在前面
设想一下这个场景:
一个老师名下有许多学生,而每个学生只能由一个老师教(班主任),那么在学生表中关联老师这个对象,在老师对象中,会有一个学生的集合。那么这种情况下,Mybatis进行SQL查询时,就不会像简单查询一样简单了。
这就涉及到一对多,多对一的问题。
问题场景中的学生类、老师类分别为(省略了getter,setter等方法):
Student类
public class Student {
private int id;
private String name;
//学生需要关联一个老师
private Teacher teacher;
private int tid;//关联的老师id
}
Teacher类
public class Teacher {
private int id; //老师id
private String name; //老师姓名
private List<Student> students; //老师对应一群学生
}
Student的相关接口
public interface StudentMapper {
List<Student> getStudentInfo(); //方法一
List<Student> getStudentInfo2(); //方法二
}
Teacher的相关接口
public interface TeacherMapper {
//根据Id查询老师
@Select("select * from teacher where id = #{tid}")
Teacher getTeacherById(@Param("tid") int id);
Teacher getTeacherById2(@Param("tid") int id);
//查询所有老师
List<Teacher> getTeachers();
}
多对一
多对一,就是以学生类(多数)为主题,他关联着“老师”这个对象,在处理查询学生信息,顺带要查询其关联的老师的信息时,可以通过如下方法:
方法一:子查询
在StudentMapper.xml配置文件中写下如下SQL语句:
<!--联表查询方式一:子查询-->
<select id="getStudentInfo" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂的属性,我们需要单独处理,对象:association,集合:collection-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacherById"/>
</resultMap>
<select id="getTeacherById" resultType="Teacher">
select * from teacher where id = #{tid}
</select>
这种方法是利用子查询。
因为学生对象关联着老师对象,所以查询学生对象时,要在父查询中嵌套一个子查询,用来查询对应的老师信息。
方法二:按照结果嵌套处理(推荐)
<!--联表查询方式二:按照结果嵌套处理-->
<select id="getStudentInfo2" resultMap="StudentTeacher2">
select s.id sid,s.name sname,t.name tname,t.id tid
from student s,teacher t
where s.tid=t.id
</select>
<resultMap id="StudentTeacher2" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
<result property="id" column="tid"/>
</association>
</resultMap>
此时,就需要在SQL语句上下功夫,将查询到的数据起别名,做ResultMap映射
一对多
一对多就是一个老师对象管理着多个学生(一个学生队列),查询某个老师时,还要把他所管理的学生队列中的信息查询出来
方法一:联表查询(推荐)
在TeacherMapper.xml配置文件中写如下SQL标签(注意:针对哪个主体做查询,就在哪个主体下的配置文件中写SQL标签)
<!--按结果嵌套查询-->
<select id="getTeacherById" resultMap="TeacherStudent">
select s.id sid,s.name sname,t.name tname,t.id tid from
student s,teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--
接下来是对集合的处理
ofType属性代表集合中的java类型
-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
方法二:子查询
<select id="getTeacherById2" resultMap="TeacherStudent2">
select * from teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<result property="id" column="id"/>
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select * from student where tid = #{id}
</select>
子查询可以不在Mapper(Dao)层的接口中写出,而仅仅只需要在xml配置文件中写出,而子查询的参数,由resultMap中的collection标签的column给出.
【注】:
- JavaType是实体类中的属性的类型
- ofType是集合中泛型的类型