说到查询,就离不开结果映射(RusultMap),因为需要把查询的结果表,映射到实体类的属性上。mybatis提供了两种方式来实现:
第一种:SqlMapper.XML:
先实现动态代理,让Mybatis自动帮我们产生实现类,调取方法并返回结果。
<?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.apefruits.mapper.GoodsFruitsMapper">
</mapper>
实习动态代理有几个需要注意的点:
1.sqlMapper.xml文件要和接口名称一致,并存放在同一个包下
2.sqlMapper.xml种的namespace要指向接口的类路径;
3.SQL语句的id要和方法名相同
4.接口的入参类型要和sqlMapper.xml中parameterType的类型相同
5.接口的返回值类型要和sqlMapper.xml中定义的每个ResultType类型相同
在多表联查的情况下,由于返回结果存在别的表的字段,ResultType不能完全识别出属性,所以需要手动配置ResultMap,之后引用即可。
首先要分析表与表之间的关系:如学生和班级之间,一个学生对应一个班级 一个班级有多个学生,所以学生和班级就是一对一,班级和学生就是一对多。
为了阅读方便,省略了getset方法和构造器。
public class Banji {
private int classid;
private String classname;
private List<Student> slist;//一对多
}
package com.ape.bean;
import java.util.Date;
public class Student {
private int sid;
private Date birthday;
private String sname;
private String ssex;
private int classid;
private Banji bj;//一对一
}
1对1的情况下:
<?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.ape.mapper.StudentMapper">
<resultMap type="Student" id="Stu_Cla_Map">
<result column="sid" property="sid"/>
<result column="birthday" property="birthday"/>
<result column="sname" property="sname"/>
<result column="ssex" property="ssex"/>
<result column="classid" property="classid"/>
<association property="bj">
<result column="classid" property="classid"/>
<result column="classname" property="classname"/>
</association>
</resultMap>
<select id="findStudentClass" resultMap="Stu_Cla_Map">
select * from student inner join class on student.classid=class.classid
</select>
</mapper>
多表联查时,所有属性必须全写,不写出来的结果映射不到对应属性上。
<resultMap>中 <association property="一对一属性名"> 然后下面的<result column="字段名"property="属性名">写对应一对一关系的另一张表的属性映射。
再看一对多的情况下:
<?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.ape.mapper.BanjiMapper">
<resultMap type="Banji" id="Cla_Stu_Map">
<result column="classid" property="classid"/>
<result column="classname" property="classname"/>
<collection property="slist" ofType="Student">
<result column="sid" property="sid"/>
<result column="birthday" property="birthday"/>
<result column="sname" property="sname"/>
<result column="ssex" property="ssex"/>
<result column="classid" property="classid"/>
</collection>
</resultMap>
<select id="findBanjibyStudent" resultMap="Cla_Stu_Map">
select * from class inner join student on student.classid=class.classid
</select>
</mapper>
利用collection标签来设置一对多
<collection property="一对多的属性名" ofType="集合内每个元素的类型">
后面再用<result column="字段名"property="属性名">写对应集合内原来类型关系的属性映射。
第二种方式就是:注解方式
需要注意的是注解中只有单表查询。
首先来说一对一:
@Result(column = "关联的字段",property = "需要映射的属性名" ,one=@One(select =“能得到属性对象的字符串"))
@Results(id = "S_C_Map" ,value = {
//@Result(column = "sid",property = "sid"),
//@Result(column = "birthday",property = "birthday"),
//@Result(column = "sname",property = "sname"),
//@Result(column = "ssex",property = "ssex"),
@Result(column = "classid",property = "classid"),
@Result(column = "classid",property = "bj",one = @One(select="com.ape.mapper.BanjiMapper.findAllBanji"))
})
@Select("select * from student")
List<Student> findStudentClass();
@Select("select * from class where classid=#{v}")
Banji findAllBanji(int classid);
由于注解方式sql语句只能写单表查询,所以学生的属性和数据库对应的字段可以不写。但需要注意的是,班级id要写,因为我们通过One=@One(select="能得到属性对象的字符串")的把得到学生表离的classid传到班级那边的sql语句了,所以得到学生表里的classid是默认值,班级表里classid是正常的。所以上面必须再手动设置映射一下,得到的结果就是学生表里是正常的classid,班级表也是。
结果如下:
一对多和一对一的方式一样只是使用的注解不同:
@Result(column = "关联的字段",property = "需要映射的属性名" ,@Many(select="通过字符反射得到的集合对象"))
@Results(value = {
@Result(column = "classid",property ="classid" ),
@Result(column = "classid",property ="slist" ,many = @Many(select = "com.ape.mapper.StudentMapper.findStudentbyclassid"))
})
@Select("select * from class ")
List<Banji> findBanjiandStudent();
@Select("select * from student where classid=#{v}")
List<Student> findStudentbyclassid(int classid);
结果如下:
在表关系中还存在多对多的关系:
再多表联查时,最好不要超过三层结构:比如:学生有课程,课程里有成绩
需要我们转换思维找到他们之间的中间表,利用中间表查询就可以得到我们想要的结果了:比如学生和课程。
一个学生有多门课,一门课有很多学生。
但是我们可以找到考试成绩。
从考试成绩来看,一门成绩对应一个课程和一个学生。
核心代码和结果如下:
创建联查映射关系
@Results({
@Result(column = "sid",property = "sid"),
@Result(column = "cid",property = "cid"),
@Result(column = "sid",property = "stu",one = @One(select = "com.ape.mapper.StudentMapper.findStudentbysid")),
@Result(column = "cid",property = "cou",one=@One(select="com.ape.mapper.CourseMapper.findCourseByCid"))
})
@Select("select * from sc")
public List<Sc> findScAll();
写出学生表和成绩表的联查
@Select("select * from student where sid=#{v}")
List<Student> findStudentbysid(int sid);
写出课程表和成绩表的联查
@Select("select * from course where cid=#{v}")
public Course findCourseByCid(int cid);
得出结果: