MyBatis的多表查询
业务装配实现多表查询(多对一)
mapper层只做单表查询操作, 在server层进行手动装配, 实现关联查询的结果
实体类
创建班级类(Clazz)和学生类(Student), 并在 Student 中添
加一个 Clazz 类型的属性, 用于表示学生的班级信息
mapper层
提供 StudentMapper 和 ClazzMapper, StudentMapper 查询所
有学生信息, ClazzMapper 根据编号查询班级信息
<mapper namespace="pers.jssd.mapper.ClazzMapper">
<select id="selById" resultType="clazz" parameterType="int">
select * from t_class where id = #{0}
</select>
</mapper>
<mapper namespace="pers.jssd.mapper.StudentMapper">
<select id="selAll" resultType="student">
SELECT * from t_student
</select>
</mapper>
service层
调用 mapper 层, 先查询所有学生, 再根据每个学生的班级
编号查询班级信息, 手动进行组装, 称之为业务装配.
@Override
public List<Student> selAll() {
SqlSession session = MyBatisUtil.getSession();
StudentMapper studentMapper = session.getMapper(StudentMapper.class);
ClazzMapper clazzMapper = session.getMapper(ClazzMapper.class);
List<Student> students = studentMapper.selAll();
for (Student student : students) {
student.setClazz(clazzMapper.selById(student.getCid()));
}
return students;
}
测试代码
public static void main(String[] args) {
StudentService studentService = new StudentServiceImpl();
List<Student> students = studentService.selAll();
System.out.println("students = " + students);
}
配置Mapper中的ResultMap实现N+1查询(多对一)
在StudentMapper中使用<association>
设置装配
association: 用于关联一个对象
- property: 指定要关联的对象
- select: 设定要继续引用的查询, namespace+id
- column: 查询时需要传递的列
<resultMap id="studentResultMap" type="student">
<!--传递的列不能省略, 不然查询不到值-->
<result property="cid" column="cid"/>
<association property="clazz" select="pers.jssd.mapper.ClazzMapper.selById" column="cid"/>
</resultMap>
<select id="selAll" resultType="student" resultMap="studentResultMap">
SELECT * from t_student
</select>
如此配置, 则查询的时候, 调用selAll的方法, 查询Student的时候, 会根据传递过去的值, 同时将clazz查询。那么,在service层就不用手动绑定查询了。
配置Mapper中的ResultMap实现联合查询(多对一)
使用sql语句进行联合查询。使用resultMap进行查询属性的映射
xml配置如下:
<resultMap id="studentResultMap" type="student">
<!--property 是java类中属性名字,column是查询语句中的名字,或者说是别名-->
<id property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="age" column="age"/>
<result property="gender" column="gender"/>
<result property="cid" column="cid"/>
<!--将association当作是另一个resultMap,javaType当作是type。column是传递的id-->
<association property="clazz" javaType="clazz" column="cid">
<id property="id" column="cid"/>
<result property="name" column="cname"/>
<result property="room" column="room"/>
</association>
</resultMap>
<select id="selAll" resultType="student" resultMap="studentResultMap">
select s.id sid,
s.name sname,
age,
gender,
cid,
c.id cid,
c.name cname,
room
from t_student s
inner join t_class c on cid = c.id;
</select>
此时,运行查询测试方法,会发现,只执行了一条sql语句,与N+1模式不同。N+1模式执行了多表的N次查询再加一次查询。
resultMap的N+1方式实现多表查询(一对多)
与多对一方式不同的就是,xml配置的时候使用的不是association标签了,而是一个collection标签。
xml配置如下
<resultMap id="clazzResultMap" type="clazz">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="room" column="room"/>
<collection property="stus" select="pers.jssd.mapper.StudentMapper.selByCid" column="id"/>
</resultMap>
<select id="selAll" resultType="clazz" resultMap="clazzResultMap">
select * from t_class
</select>
resultMap的关联方式实现多表查询(一对多)
同样的,使用resultMap定义映射关系,并通过collection指定集合属性泛型的映射关系,可以把collection看成一个resultMap使用。ofType属性表示集合的泛型,可以写全限定路径或者别名
<resultMap id="clazzResultMap" type="clazz">
<id property="id" column="cid"/>
<result property="name" column="cname"/>
<result property="room" column="room"/>
<collection property="stus" javaType="list" ofType="student" column="id">
<id property="id" column="sin"/>
<result property="name" column="sname"/>
<result property="age" column="age"/>
<result property="gender" column="gender"/>
<result property="cid" column="cid"/>
</collection>
</resultMap>
<select id="selAll" resultType="clazz" resultMap="clazzResultMap">
select s.id sid,
s.name sname,
age,
gender,
cid,
c.id cid,
c.name cname,
room
from t_student s
inner join t_class c on cid = c.id;
</select>
使用auto-mapping机制实现多表查询
通过 MyBatis 的 Auto-Mapping 机制及数据库查询时的别
名结合, 可以方便的实现多表查询.
SQL 语句中, 别名出现特殊符号时, 必须进行处理. MySQL
可以使用(``)符号, Oracle 可以使用("")符号.
<!--mysql-->方式
<mapper namespace="com.bjsxt.mapper.StudentMapper">
<select id="selAll" resultType="student">
select s.id, s.name, s.age, s.gender, s.cid, c.id `clazz.id`,
c.name `clazz.name`, c.room `clazz.room`
from t_student s
left join t_class c
on s.cid=c.id
</select>
</mapper>