mybatis关联查询(一对一与一对多)

以前在写小demo的时候对于具有关联关系的对象,都是分别查的,但其实mybatis可以直接进行关联查询,今天就来详细讲一下用mybatis怎样进行一对一和一对多的关联查询.


一对一关系:

需求:假设有一个User类,一个Car类,一个User对应这一辆Car,查询User信息的同时查询出他的Car的信息.

期望查询结果:
在这里插入图片描述

User.java

package com.wantao.bean;
import lombok.Data;
@Data
public class User {
	private Integer userId;
	private String userName;
	private Integer cId;
	private Car car;
}

 
 

Car.java

package com.wantao.bean;
import lombok.Data;
@Data
public class Car {
	private Integer carId;
	private String  carName;
}

 
 

方法一:使用自动结果映射处理一对一关系

<mapper namespace="com.wantao.dao.UserDao">
	<select id="findUserById" resultType="com.wantao.bean.User">
		select u.user_id,u.user_name,u.c_id,c.car_id "car.carId",c.car_name "car.carName"
		from tb_user u
		left join tb_car c on u.c_id = c.car_id
		where u.user_id=#{id}
	</select>
</mapper>

 
 

           使用自动结果映射就是通过别名的方式(car.carId,car.carName)让Mybatis自动将值匹配到对应的字段上

方法二:使用resultMap配置一对一映射

UserMapper.xml

<mapper namespace="com.wantao.dao.UserDao">
	<resultMap type="com.wantao.bean.User" id="map1">
		<id column="user_id" property="userId"></id>
		<result column="user_name" property="userName" />
		<result column="c_id" property="cId" />
		<!--Car相关的属性加上了car.-->
		<result column="car_id" property="car.carId" />
		<result column="car_name" property="car.carName" />
	</resultMap>
	<select id="findUserById" resultMap="map1">
		select
		u.user_id,u.user_name,u.c_id,c.car_id ,c.car_name
		from tb_user u
		left join tb_car c on u.c_id = c.car_id
		where u.user_id=#{id}
	</select>
</mapper>

 
 

           可以看到我们select的返回值不是resultType而是变为了resultMap,而且Car相关的resultproperty属性都带上了car.前缀(如果你在select里为Car的属性设置了别名,resultMap中就不用再带car.的前缀了)
           上面把UserCar写在了一个resultMap中,如果一个User除了拥有Car还拥有Dog,Cat…之类的话,就显的很复杂,其实我们也可以把他们分别写在一个resultMap中,通过resultMapextends属性进行继承,要注意的是Car的属性还是要带上car.的前缀

UserMapper.xml

<mapper namespace="com.wantao.dao.UserDao">
    <!--map1返回的是User本身的基本属性-->
	<resultMap type="com.wantao.bean.User" id="map1">
		<id column="user_id" property="userId"></id>
		<result column="user_name" property="userName" />
		<result column="c_id" property="cId" />
	</resultMap>
	<!--map2继承了map1返回的是User和Car的基本属性-->
	<resultMap type="com.wantao.bean.User" id="map2" extends="map1">
	    <result column="car_id" property="car.carId" />
		<result column="car_name" property="car.carName" />
	</resultMap>
	<select id="findUserById" resultMap="map2">
		select
		u.user_id,u.user_name,u.c_id,c.car_id ,c.car_name
		from tb_user u
		left join tb_car c on u.c_id = c.car_id
		where u.user_id=#{id}
	</select>
</mapper>

 
 

方法三:使用resultMap的association配置一对一映射

UserMapper.xml

<mapper namespace="com.wantao.dao.UserDao">
	<resultMap type="com.wantao.bean.User" id="map1">
		<id column="user_id" property="userId"></id>
		<result column="user_name" property="userName" />
		<result column="c_id" property="cId" />
		<association property="car" javaType="com.wantao.bean.Car">
		       <id column="car_id" property="carId"/>
		       <result column="car_name" property="carName"/>
		</association>
	</resultMap>
	<select id="findUserById" resultMap="map1">
		select
		u.user_id,u.user_name,u.c_id,c.car_id ,c.car_name
		from tb_user u
		left join tb_car c on u.c_id = c.car_id
		where u.user_id=#{id}
	</select>
</mapper>

 
 

           不知道你们发现了没有,这里的 Car的属性,并不需要带上car.的前缀.同样如果你觉得把UserCar写在了一个resultMap中不太好,你也可以让association直接返回一个resultMap类型

UserMapper.xml

<mapper namespace="com.wantao.dao.UserDao">
	<resultMap type="com.wantao.bean.User" id="map1">
		<id column="user_id" property="userId"></id>
		<result column="user_name" property="userName" />
		<result column="c_id" property="cId" />
		<!--设置association的返回为resultMap-->
		<association resultMap="map2" property="car"
			javaType="com.wantao.bean.Car">
		</association>
	</resultMap>
	<resultMap type="com.wantao.bean.Car" id="map2">
		<id column="car_id" property="carId" />
		<result column="car_name" property="carName" />
	</resultMap>
	<select id="findUserById" resultMap="map1">
		select
		u.user_id,u.user_name,u.c_id,c.car_id ,c.car_name
		from tb_user u
		left
		join tb_car c on u.c_id = c.car_id
		where u.car_id=#{id}
	</select>
</mapper>

 
 

方法四:使用association的嵌套查询
           前面的三种通过复杂的查询获取结果,都属于关联的嵌套结果映射,即通过一次SQL查询根据表或指定的属性映射到不同的对象中。除了这种方法,还有一种关联的嵌套查询,即简单的SQL通过多次查询转换为我们需要的结果(类似于手动的执行多次SQL)

UserMapper.xml

<mapper namespace="com.wantao.dao.UserDao">
	<resultMap type="com.wantao.bean.User" id="map1">
		<id column="user_id" property="userId"></id>
		<result column="user_name" property="userName" />
		<result column="c_id" property="cId" />
		<association select="com.wantao.dao.CarDao.findCarById"
			property="car" column="c_id">
		</association>
	</resultMap>
	<select id="findUserById" resultMap="map1">
		select
		*
		from tb_user u
		where u.user_id=#{id}
	</select>
</mapper>

 
 

CarMapper.xml

<mapper namespace="com.wantao.dao.CarDao">
	<select id="findCarById" resultType="com.wantao.bean.Car">
		select car_id,car_name
		from
		tb_car
		where car_id=#{id}
	</select>
</mapper>

 
 

在这里插入图片描述
通过打印的sql语句可以发现它是执行了两次不同的sql语句,先查询了User,然后又查询了Car,要注意的是column="c_id"属性,mybatis是先查询出Userc_id然后将c_id作为参数传递给CarMapper.

一对多关系:

需求:假设有一个User类,一个Car类,一个User对应这多辆Car,查询User信息的同时查询出他所有的Car的信息.

期望查询结果:
在这里插入图片描述
User.java

package com.wantao.bean;
import java.util.List;
import lombok.Data;
@Data
public class User {
	private Integer userId;
	private String userName;
	private List<Car> cars;
}

 
 

Car.java

package com.wantao.bean;
import lombok.Data;
@Data
public class Car {
	private Integer carId;
	private String  carName;
    private Integer uId;
}

 
 

UserMapper.xml

<mapper namespace="com.wantao.dao.UserDao">
	<resultMap type="com.wantao.bean.User" id="map1">
		<id column="user_id" property="userId"></id>
		<result column="user_name" property="userName" />
		<collection property="cars" ofType="com.wantao.bean.Car">
		   <id property="carId" column="car_id"/>
		   <result property="carName" column="car_name"/>
		   <result property="uId" column="u_id"/>
		</collection>
	</resultMap>
	<select id="findUserById" resultMap="map1">
		select
		user_id,user_name,car_id,car_name,u_id
		from tb_user u
		left join tb_car c on u.user_id = c.u_id
		where u.user_id=#{id}
	</select>
</mapper>

 
 

一对一的方法基本上都可以用到一对一上,这里就不重复举例了,只简单的举这一个例子.
有三个注意点:
                      ①.User类里的cars的类型是List<Car>
                      ②.使用的是collection,而不是association
                       .collection上使用的是ofType而不是javaType(这点要尤其注意,我一开始使用了javaType,报下面的错

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: Could not set property 'cars' of 'class com.wantao.bean.User' with value 'Car(carId=1, carName=法拉利, uId=1)' Cause: java.lang.IllegalArgumentException: argument type mismatch

 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
MyBatis-Plus是一款MyBatis的增强工具,它提供了很多实用的功能,比如一对多关联查询。在MyBatis-Plus中,一对多关联查询可以通过使用@TableName注解和@TableField注解来实现。 假设我们有两张表,一张是学生表,另一张是课程表,一个学生可以选多门课程,那么我们就可以用一对多关联查询来查询某个学生选的所有课程。 首先,在学生表中定义一个属性List<Course> courses,并使用@TableField注解将该属性与课程表的外键关联起来: ``` public class Student { @TableId private Long id; private String name; @TableField(exist = false) private List<Course> courses; } ``` 然后,在课程表中定义一个属性Long studentId,并使用@TableField注解将该属性与学生表的主键关联起来: ``` public class Course { @TableId private Long id; private String name; @TableField("student_id") private Long studentId; } ``` 最后,我们使用MyBatis-Plus提供的wrapper类进行关联查询: ``` QueryWrapper<Student> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("id", studentId); List<Student> students = studentMapper.selectList(queryWrapper); for (Student student : students) { QueryWrapper<Course> courseQueryWrapper = new QueryWrapper<>(); courseQueryWrapper.eq("student_id", student.getId()); List<Course> courses = courseMapper.selectList(courseQueryWrapper); student.setCourses(courses); } ``` 以上就是MyBatis-Plus实现一对多关联查询的方法。如果您还有其他问题或需要进一步的帮助,请随时提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Selenium399

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值