以前在写小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
相关的result
的property
属性都带上了car.
前缀(如果你在select
里为Car
的属性设置了别名,resultMap
中就不用再带car.
的前缀了)
上面把User
和Car
写在了一个resultMap
中,如果一个User
除了拥有Car
还拥有Dog
,Cat
…之类的话,就显的很复杂,其实我们也可以把他们分别写在一个resultMap
中,通过resultMap
的extends
属性进行继承,要注意的是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.
的前缀.同样如果你觉得把User
和Car
写在了一个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
是先查询出User
的c_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