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

一对一关系:

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

期望查询结果:

mybatiesplus关联查询 mybatis关联查询一对一_User

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>

mybatiesplus关联查询 mybatis关联查询一对一_java_02


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

一对多关系:

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

期望查询结果:

mybatiesplus关联查询 mybatis关联查询一对一_mybatiesplus关联查询_03


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