Mybatis–关联查询
当查询内容涉及到具有关联关系的多个表时,就需要使用关联联查。根据表与表间的关联关系的不同,关联查询分为四种:
- 一对一关联查询
- 一对多关联查询
- 多对一关联查询
- 多对多关联查询
一、一对一关联查询
一对多关联查询是指,在查询一对象的时候,同时将其所关联的一个对象也都查询出来。
例:一张身份证卡只对应一个人
一个人只对应一张身份证
1.定义实体
Card:
public class Card {
private int cardId;
private String cardCode;
private int perId;
//一对一关系定义模型对象
private Person person;
}
Person:
public class Person {
private int perId;
private String perName;
private Card card;
}
2.定义数据库:
card表
person表
3.定义dao接口
public interface OneToOneDao {
//根据人员编号获取人员信息以及卡号信息
Card queryCardByPerId(int perId);
Person queryPerByCardId(int cardId);
}
4.测试类:
public class TestDao {
SqlSessionFactory sqlSessionFactory = BuilderSessionFactory.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession(true);
@Test
public void cardAndPerson() {
OneToOneDao oneToOneDao = sqlSession.getMapper(OneToOneDao.class);
System.out.println(oneToOneDao.queryCardByPerId(1000));
}
}
5.写映射文件
<mapper namespace="com.mybatisTest.dao.OneToOneDao">
<select id="queryCardByPerId" parameterType="int" resultMap="cardandperson">
select * from card c
join person p
on c.perid = p.perid
where c.perid = #{perid}
</select>
<select id="queryPerByCardId" parameterType="int" resultMap="personandcard">
select * from person p
join card c
on c.perid = p.perid
where p.perid = #{perid}
</select>
<resultMap id="cardandperson" type="Card">
<id column="cardid" property="cardId"></id>
<result column="cardcode" property="cardCode"></result>
<result column="perid" property="perId"></result>
<!--one-to-one映射对象模型-->
<association property="person" javaType="Person">
<id column="perid" property="perId"></id>
<result column="pername" property="perName"></result>
</association>
</resultMap>
<resultMap id="personandcard" type="Person">
<id column="perid" property="perId"></id>
<result column="pername" property="perName"></result>
<!--one-to-one映射对象模型-->
<association property="card" javaType="Card">
<id column="cardid" property="cardId"></id>
<result column="cardcode" property="cardCode"></result>
<result column="perid" property="perId"></result>
</association>
</resultMap>
</mapper>
注意,此时即使字段名与属性名相同,在中也要写出他们的映射关系。因为框架是依据封装对象的。
在映射文件中使用标签体现出两个实体对象间的关联关系。其两个属性的意义为:
- property:关联的属性名,就是将用户对象关联到Order的那个属性
- javaType: 属性的类型
二、一对多关联查询
一对多关联查询是指,在查询一对象的时候,同时将其所关联的多放对象也都查询出来。
例:班级和间的一对多关系
若定义的是双向关联,即双方的属性中均有对方的对象作为作用域属性出现
Classes:
public class Classes {
private int classId;
private String classCode;
List<Student> students;
}
Student:
public class Student {
private int stuId;
private String stuName;
private String stuSex;
private String stuAge;
private int classId;
private Classes classes;
}
2.定义数据库:
calsses表:
student表:
3.定义dao接口
public interface OneToManyDao {
Classes queryClassByStudent(int stuId);
List<Student> queryStudentByClass(int classId);
}
4.测试类:
@Test
public void classandstu(){
OneToManyDao oneToManyDao = sqlSession.getMapper(OneToManyDao.class);
System.out.println(oneToManyDao.queryClassByStudent(1000));
}
@Test
public void sutandClasses(){
OneToManyDao oneToManyDao = sqlSession.getMapper(OneToManyDao.class);
System.out.println(oneToManyDao.queryStudentByClass(1000));
}
5.写映射文件
<mapper namespace="com.mybatisTest.dao.OneToManyDao">
<select id="queryClassByStudent" resultMap="classandstu" parameterType="int">
select * from classes c
join student s
on c.classid = s.classid
where s.stuid = #{stuId}
</select>
<select id="queryStudentByClass" parameterType="int" resultMap="stuandclass" >
select * from student s
join classes c
on c.classid = s.classid
where c.classid = #{classId}
</select>
<resultMap id="stuandclass" type="Student">
<id column="stuid" property="stuId"/>
<result column="stuname" property="stuName"/>
<result column="stusex" property="stuSex"/>
<result column="stuage" property="stuAge"/>
<collection property="classes" ofType="Classes">
<id column="classid" property="classId"></id>
<result column="classcode" property="classCode"></result>
</collection>
</resultMap>
<resultMap id="classandstu" type="Classes">
<id column="classid" property="classId"></id>
<result column="classcode" property="classCode"></result>
<!--one-to-many映射集合对象模型-->
<collection property="students" ofType="Student" >
<id column="stuid" property="stuId"/>
<result column="stuname" property="stuName"/>
<result column="stusex" property="stuSex"/>
<result column="stuage" property="stuAge"/>
</collection>
</resultMap>
</mapper>
- collection:对关联查询到的多条记录映射到集合对象中
- property:将查询到的多条记录映射到User类的那个属性中
- ofType: 指明集合中的元素的类型
三、多对一关联查询
这里的多对一关联查询是指,在查询多方对象的时候,同时将其所关联的一方对象也查询出来。
由于查询多方对象时也是一个一个查询,所以多对一关联查询,其实就是一对一关联查询。即一对一关联查询的实现方式与多对一的实现方式是相同的。
例如:学生Student和班级classes的关系
代码在一对多关联查询中,此次省略。。。。。。
四、多对多关联查询
多对多关联关系,例如一个学生可以选多门课程,而一门课程可以由多个学生选择。多对多关系,其实是由两个互反的一对多关系组成。一般情况下,多对多关系都会通过一个中间表来建立,例如选课表
思路可按照 双向一对多来
1.定义实体:
在定义双向关联
Course:
public class Course {
private int courId;
private String courName;
List<Student> students;
}
Student:
public class Student {
private int stuId;
private String stuName;
private String stuSex;
private String stuAge;
private int classId;
private List<Course> courses;
}
2.定义数据库
在多对多的关系时定义数据库,需要用到中间表来关联两个表
student_course表
course表
student表
3.定义dao接口
public interface ManyToManyDao {
List<Course> queryCoursesAndStudentsByStudentId(int stuId);
List<Student> queryStudentsAndCoursesByCourseId(int i);
}
4.测试类:
@Test
public void classesandstus(){
ManyToManyDao manyToManyDao = sqlSession.getMapper(ManyToManyDao.class);
System.out.println(manyToManyDao.queryCoursesAndStudentsByStudentId(1000));
}
@Test
public void studentandclass(){
ManyToManyDao manyToManyDao = sqlSession.getMapper(ManyToManyDao.class);
System.out.println(manyToManyDao.queryStudentsAndCoursesByCourseId(1000));
}
5.写映射文件
<mapper namespace="com.mybatisTest.dao.ManyToManyDao">
<select id="queryCoursesAndStudentsByStudentId" resultMap="courseandstudent" parameterType="int">
SELECT * FROM course c
join student_course sc
on sc.courid = c.courid
join student s
on s.stuid = sc.stuid
where s.stuid = #{stuId}
</select>
<select id="queryStudentsAndCoursesByCourseId" parameterType="int" resultMap="studentandcourse">
SELECT * FROM student s
join student_course sc
on s.stuid = sc.stuid
join course c
on sc.courid = c.courid
where c.courid = #{courId}
</select>
<resultMap id="courseandstudent" type="Course">
<id property="courId" column="courid"></id>
<result column="courname" property="courName"></result>
<collection property="students" ofType="Student">
<id column="stuid" property="stuId"/>
<result column="stuname" property="stuName"/>
<result column="stusex" property="stuSex"/>
<result column="stuage" property="stuAge"/>
</collection>
</resultMap>
<resultMap id="studentandcourse" type="Student">
<id column="stuid" property="stuId"/>
<result column="stuname" property="stuName"/>
<result column="stusex" property="stuSex"/>
<result column="stuage" property="stuAge"/>
<collection property="courses" ofType="Course">
<id property="courId" column="courid"></id>
<result column="courname" property="courName"></result>
</collection>
</resultMap>
</mapper>
总结
mybatis全局配置文件中通过mapUnderscoreToCamelCase可以开启sql中的字段和javabean中的骆驼命名法的字段进行自动映射
掌握resultMap元素常见的用法
一对一关联查询使用resultMap->association元素(2种方式)
一对多查询使用resultMap->collection元素(2种方式)
resultMap中使用id元素主要在复杂的关联查询中可以提升效率,可以通过这个来判断记录的唯一性,如果没有这个,需要通过所有的result相关的列才能判断记录的唯一性
建议
实体类中最好只定义一些和单表字段关联的属性,不要掺杂着其他对象的引用。