MyBatis多表查询

本文详细介绍了MyBatis在多表查询中的映射方式,包括Auto Mapping特性、resultMap标签的单表映射、多表查询关联单个对象和集合对象的映射。通过实例展示了映射机制的工作原理,强调了属性名和setter方法在自动映射中的作用,并提到了在业务层进行多表查询装配的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用mybatis访问数据库,将数据库表与pojo对象映射的方式有两种:Auto Mapping特性自动映射和resultMap标签手动映射。

Auto Mapping特性

当数据库表列名与实体类的属性名一致时可以使用自动映射。

例如,数据库表结构为:

在这里插入图片描述

实体类设计为:
在这里插入图片描述

Sql映射文件:

<?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.test.mapper">
	<select id="selectAll" resultType="com.test.pojo.People">
		select * from people
	</select>
</mapper>

因为数据库表列名和实体类属性名相同,只需要resultType指定返回值类型,不需要配置resultMap属性即可实现自动映射。

测试sql语句执行:

public class Test {
	public static void main(String[] args) throws IOException {
		InputStream is = Resources.getResourceAsStream("mybatis.xml");
		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
		SqlSession session = factory.openSession();
		
		List<People> selectList = session.selectList("com.test.mapper.selectAll");
		session.commit();
		for (People people : selectList) {
			System.out.println(people);
		}
	}
}

在这里插入图片描述

从结果可以看到,正确的执行了查询全部的sql语句,并且实体类的每一个属性值都成功映射到了。

下面我们修改一下实体类的name属性名,使之与数据库表的列名不同:

在这里插入图片描述

我们再看一下执行结果:

在这里插入图片描述

从结果看到,此时它依然能够正确的执行,并正确映射,与我们之前的前提“数据库表列名与实体类属性名相同”不相符。

在实体类中,除了属性声明外,我们还定义了属性的getter个setter方法,所以很有可能此时是通过setter方法进行的自动映射,为了验证,再把setName方法名改为setName1测试一下:

在这里插入图片描述
在这里插入图片描述

Sql语句能正常执行,但是查询结果中实体类对象的name属性值变成了null,说明此时name属性没有正确的映射。那么mybatis是通过实体类的属性名还是setter方法来进行自动映射的呢?

我们再将第一次执行的实体类的所有属性的setter方法删掉,测试一下是否能自动映射:

在这里插入图片描述

在这里插入图片描述

依然可以正确的执行自动映射,我们在此基础上修改name属性名:

在这里插入图片描述
在这里插入图片描述

从上结果可以看到,此时属性name就不能成功自动映射。

再试一下属性名可映射,setter方法无法映射的情况:

在这里插入图片描述

在这里插入图片描述

此时也可以进行映射。
那么我们就可以得出结论:

1、通过属性名映射和通过setter方法映射的方式是互补的。
2、当实体类中有setter方法(属性名无法映射)时,mybatis自动映射机制是通过setter方法执行的,setter方法名称正确(set+列名)即可正确映射;
3、当实体类中没有setter方法(setter方法无法映射)时,mybatis自动映射机制是通过属性名进行的,当属性名与列名相同即可完成映射。
4、mybatis自动映射不区分大小写;
5、可以在sql语句中给列名设置别名与实体类进行映射;

<select id="selectAll" resultType="com.test.pojo.People">
	select id, name as name1, age from people
</select>

6、映射是通过反射技术实现的。

resultMap标签单表映射

除了使用mybatis的Auto Mapping特性自动映射外,还可以使用resultMap标签进行手动映射。

<?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.test.mapper">
	
	<resultMap type="com.test.pojo.People" id="peoMap">
		<id column="id" property="id"/>
		<result column="name" property="name1"/>
		<result column="age" property="age"/>
	</resultMap>
	
	<select id="selectAll" resultMap="peoMap">
		select * from people
	</select>
</mapper>

手动映射需要编写resultMap标签,select中需要使用resultMap属性声明使用到的resultMap标签的id属性,同时不再需要配置resultType属性。

resultMap标签中需要配置resultType属性声明映射的实体类,使用id属性标识此resultMap标签。同时映射的数据库表中主键字段需要使用id标签配置映射,其他字段使用result标签配置映射。

上述mapper文件映射的实体类如下:

在这里插入图片描述

从下面的执行结果看,可以正确的映射:
在这里插入图片描述

也可以两种映射方法混合使用,如下:

<?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.test.mapper">
	
	<resultMap type="com.test.pojo.People" id="peoMap">
		<result column="name" property="name1"/>
	</resultMap>
	
	<select id="selectAll" resultMap="peoMap">
		select * from people
	</select>
</mapper>

即name列使用resultMap手动映射,其他列使用Auto Mapping自动映射。

resultMap标签实现多表查询关联单个对象

N+1方式

N+1方式,先查询出某个表的全部信息,根据这个表的信息查询另一个表的信息,如下所示:

<resultMap type="student" id="stuMap">
	<id property="id" column="id"/>
	<result property="name" column="name"/>
	<result property="age" column="age"/>
	<result property="tid" column="tid"/>
	<!-- 如果关联一个对象-->
	<association property="teacher"
		select="com.test.mapper.TeacherMapper.selById"
		column="tid">
	</association>
</resultMap>
<select id="selAll" resultMap="stuMap">
	select * from student
</select>

<association> 标签用于装配一个对象。其中property属性用于声明对象在类中的属性名,select属性用于声明通过哪个查询查询出这个对象的信息,column属性用于声明把当前表的哪个列的值做为参数传递给另一个查询。

另外,使用N+1 方式.时如果列名和属性名相同可以不配置,使用Auto mapping 特性.但是mybatis 默认只会给列专配一次,即tid被传入查询teacher信息的sql语句中之后不会再映射到student中的tid属性中。所以上面的sql语句映射可以简写成如下形式:

<resultMap type="student" id="stuMap">
	<result column="tid" property="tid"/>
	<!-- 如果关联一个对象 -->
	<association property="teacher" select="com.test.mapper.TeacherMapper.selById" column="tid"></association>
</resultMap>
<select id="selAll" resultMap="stuMap">
	select * from student
</select>

TeacherMapper中的sql语句映射为:

<select id="selById" resultType="teacher" parameterType="int">
	select * from teacher where id=#{0}
</select>

Student实体类如下:

package com.test.pojo;

public class Student {
	private int id;
	private String name;
	private int age;
	private int tid;
	private Teacher teacher;
	
	public Teacher getTeacher() {
		return teacher;
	}
	public void setTeacher(Teacher teacher) {
		this.teacher = teacher;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public int getTid() {
		return tid;
	}
	public void setTid(int tid) {
		this.tid = tid;
	}
	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", age=" + age + ", tid=" + tid + ", teacher=" + teacher + "]";
	}
	
}

Teacher实体类如下:

package com.test.pojo;

public class Teacher {
	private int id;
	private String name;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Teacher [id=" + id + ", name=" + name + "]";
	}
}

测试查询结果:

package com.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.test.pojo.Student;


public class Test {
	public static void main(String[] args) throws IOException {
		
		
		
		InputStream is = Resources.getResourceAsStream("mybatis.xml");
		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
		SqlSession session = factory.openSession();
		
		
		List<Student> list = session.selectList("com.test.mapper.StudentMapper.selAll");
		System.out.println(list);
		
		session.close();
		System.out.println("程序执行结束");
	}
}

在这里插入图片描述

查询的log来看,是先执行了查询Student表的sql语句,再执行的查询Teacher表的sql语句。

联合查询方式

即使用连接查询方式,需要使用<association> 标签装配Teacher对象,javaType属性用于声明返回的Java对象类型。如下sql语句映射使用的是左外连接方式查询,并且resultMap中使用的别名映射。

<resultMap type="Student" id="stuMap1">
		<id column="sid" property="id"/>
		<result column="sname" property="name"/>
		<result column="age" property="age"/>
		<result column="tid" property="tid"/>
		<association property="teacher" javaType="Teacher" >
			<id column="tid" property="id"/>
			<result column="tname" property="name"/>
		</association>
	</resultMap>
	<select id="selAll1" resultMap="stuMap1">
		select s.id sid,s.name sname,age age,t.id tid,t.name tname FROM student s left outer join teacher t on s.tid=t.id
	</select>

resultMap标签实现多表查询关联集合对象

关联集合对象,即用于一对多的场景,即一个老师对应多个学生。

Teacher实体类:

package com.test.pojo;

import java.util.List;

public class Teacher {
	private int id;
	private String name;
	private List<Student> list;
	
	public List<Student> getList() {
		return list;
	}
	public void setList(List<Student> list) {
		this.list = list;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Teacher [id=" + id + ", name=" + name + ", list=" + list + "]";
	}
}

Teacher类中list属性为老师对应的学生集合。

Student实体类:

package com.test.pojo;

public class Student {
	private int id;
	private String name;
	private int age;
	private int tid;
	private Teacher teacher;
	
	public Teacher getTeacher() {
		return teacher;
	}
	public void setTeacher(Teacher teacher) {
		this.teacher = teacher;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public int getTid() {
		return tid;
	}
	public void setTid(int tid) {
		this.tid = tid;
	}
	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", age=" + age + ", tid=" + tid + ", teacher=" + teacher + "]";
	}
	
}

N+1方式

TeacherMapper中sql语句映射使用N+1方式,如下:

<resultMap type="teacher" id="mymap">
	<id column="id" property="id"/>
	<result column="name" property="name"/>
	<collection property="list" select="com.test.mapper.StudentMapper.selByTid" column="id"></collection>
</resultMap>
<select id="selAll" resultMap="mymap">
	select * from teacher
</select>

StudentMapper中sql语句映射如下:

<select id="selByTid" parameterType="int" resultType="student">
	select * from student where tid=#{0}
</select>

测试sql执行代码:

package com.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.test.pojo.Teacher;


public class Test {
	public static void main(String[] args) throws IOException {
		InputStream is = Resources.getResourceAsStream("mybatis.xml");
		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
		SqlSession session = factory.openSession();
		
		
		List<Teacher> list = session.selectList("com.test.mapper.TeacherMapper.selAll");
		for (Teacher teacher : list) {
			System.out.println(teacher);
		}
//		System.out.println(list);
		
		session.close();
		System.out.println("程序执行结束");
	}
}

在这里插入图片描述

联合查询方式

TeacherMapper中sql语句映射使用左连接:

<resultMap type="teacher" id="mymap1">
		<id column="tid" property="id"/>
		<result column="tname" property="name"/>
		<collection property="list" ofType="student" >
			<id column="sid" property="id"/>
			<result column="sname" property="name"/>
			<result column="age" property="age"/>
			<result column="tid" property="tid"/>
		</collection>
	</resultMap>
	<select id="selAll1" resultMap="mymap1">
		select t.id tid,t.name tname,s.id sid,s.name sname,age,tid from teacher t LEFT JOIN student s on t.id=s.tid;
	</select>

使用Auto Mapping 结合别名实现多表查询

Auto Mapping实现多表查询,只能使用连接查询结合别名实现,并且不支持关联集合对象,只能关联单个对象。

	<select id="selAll" resultType="student">
		select t.id `teacher.id`,t.name `teacher.name`,s.id id,s.name name,age,tid 
from student s LEFT JOIN teacher t on t.id=s.tid
	</select>

业务层装配实现多表查询

除了在mybatis的sql语句映射中来实现多表查询外,我们还可以分别查询数据库表,然后再业务层Java代码中进行关联装配。

        //查询学生信息
List<Student> list = studentMapper.selByPage(pi);
		//查询出每个学生对应的老师信息
		TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);
		for (Student student : list) {
			student.setTeacher(teacherMapper.selById(student.getTid()));
		}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值