多表联查
- 一、步骤一:创建pojo实体类
- 二、步骤二:明确两个实体类之间的关系
- 三、步骤三:修改pojo实体类
- 四、步骤四:编写Mapper接口
- 五、步骤五:编写Mapper映射文件
- 题目1:通过订单id查询订单详情以及所属用户
- 题目2:通过用户id查询用户信息以及她所有的订单
- 六、补充
在数据库查询中,很多时候不只是查询一张表,而是需要将多张表结合起来才能获得需要的数据,下面介绍在mybatis中怎么实现多表联查(前提是所有的依赖均已配置完成)
一、步骤一:创建pojo实体类
将需要用到的表全部创建成java的实体类,导入lombok依赖(自动生成get、set等方法)
User 用户表 Order 订单表
@Data
public class User {
private Integer ID;
private String username;
private String PASSWORD;
private String sex;
private Date brithday;
private String address;
}
二、步骤二:明确两个实体类之间的关系
一个用户可以有多条订单,而一条订单只属于一个用户
所以;:用户对订单是1对多
的关系
在设计数据库时(黄色部分)
:在多的一方(tb_order)中添加一个外键,与tb_user的主键对应(图中为uid)
在设计java对象时(红色部分)
: 需要根据题目进行pojo类的编写(具体看步骤三)
三、步骤三:修改pojo实体类
先分析清楚题目 如:
①:根据id查询订单以及订单的所属用户信息
=>
返回的数据是tb_order表中的数据+tb_user表中的数据,需要修改的实体类是Order,因为是根据order的id查询的
//需要在Order的实体类中引入User对象
public class Order {
private Integer id;
private Integer userid;
private Date createtime;
private String state;
// 多对一
private User user = new User();
}
②:根据用户id查询她的各类订单
=>
返回的数据是tb_user+tb_order表中的数据,但是不同与上面的是:由于订单有多条所以订单需要用集合来装,而查询出的数据是要根据用户的id查询所有需要修改User类
// 需要在User表中的实体类中引入数据类型为Order的集合
public class User implements Serializable {
private Integer ID;
private String username;
private String PASSWORD;
private String sex;
private Date brithday;
private String address;
// 一对多
private List<Order> orders = new ArrayList<>();
}
四、步骤四:编写Mapper接口
public interface UserMapper {
// 通过订单id查询订单详情以及所属用户
Order selectOrderAndInfoById(@Param("oid") int id);
// 通过用户id查询该用户的所有订单
User selectByUserIdForOrder(@Param("uid") int id);
// 根据id查询用户
User selectUserByid(@Param("uid") int id);
}
五、步骤五:编写Mapper映射文件
需要指定该映射文件是步骤四的Mapper,在namespace中指定
重点来了:
题目1:通过订单id查询订单详情以及所属用户
需要知道的是我们关联的是两张表
,如果直接用下面的sql语句则只能查出订单的信息而订单所属用户则为空
,这是因为在执行过程中Order会自动映射到tb_order的内容,但是在Order表中定义的User对象则无法自动映射
到tb_user表中的内容
SELECT u.ID ,u.username,u.PASSWORD,u.sex,u.brithday,u.address,o.id oid,o.userid,o.createtime,o.state
FROM tb_user u JOIN tb_order o
ON u.ID = o.userid
WHERE u.id= #{uid}
所以我们得手动映射User类
,需要使用到resultMap
总体代码如下:
<!-- todo 根据id查询订单以及对应的用户 -->
<sql id="selectById">
u.ID ,u.username,u.PASSWORD,u.sex,u.brithday,u.address,
o.id oid,o.userid,o.createtime,o.state
</sql>
<resultMap id="selectParent" type="Order">
<id property="id" column="oid"/>
<result property="userid" column="userid"/>
<result property="createtime" column="createtime"/>
<result property="state" column="state"/>
</resultMap>
<resultMap id="selectChildren" type="Order" extends="selectParent">
<association property="user" javaType="User" select="selectUserByid" column="userid"/>
</resultMap>
<select id="selectOrderAndInfoById" resultMap="selectChildren">
SELECT
<include refid="selectById"/>
FROM tb_user u JOIN tb_order o
ON u.ID = o.userid
WHERE o.id = #{oid}
</select>
<!-- 根据id查询用户-->
<select id="selectUserByid" resultType="User">
SELECT * FROM tb_user WHERE ID = #{uid}
</select>
selectParent
为手动映射的Order类的Map,selectChildren
为手动映射的User类的Map,由于需要返回的订单类
的数据所有type
中填写Order类,children
继承了parent
那么children中也会有parent的映射,所有selectChildren
的map中就有了Order+User
的映射
这个时候再<select>
标签resultMap
中只需要传入selectChildren
就可以了
<association property="user" javaType="User" select="selectUserByid" column="userid"/>
association
:因为在Order类中的User对象是单
个,所以使用该关键字
property
:对应Order表中的创建的User对象名
javaType
:property对应的数据类型
select
:就是指映射user对象去改方法中找,刚刚selectUserByid
方法返回的就是一个User
对象,这样就免去了手动一 一映射的麻烦
column
:但是selectUserByid
需要传入一个参数,这里传入的userid是从Order
中查询得到的然后再传给该方法去查询对应的User
题目2:通过用户id查询用户信息以及她所有的订单
学会了上面的知识后,这里就只是发生了一点点的变化
同样也是,是根据用户的id查询所以需要在User类中进行操作,而一个用户有多条订单,所以需要在用户类User中定义一个Order类型的集合,mybatis也只能映射User类和tb_user表,无法映射Order类和tb_order表,所以我们也需要手动映射
总体代码如下:
<!-- todo 根据用户id查询订单 -->
<resultMap id="Userparent" type="User">
<id column="ID" property="ID"/>
<result column="username" property="username"/>
<result column="PASSWORD" property="PASSWORD" />
<result column="sex" property="sex" />
<result column="brithday" property="brithday" />
<result column="address" property="address" />
<collection property="orders" ofType="Order" >
<id column="oid" property="id"/>
<result column="userid" property="userid"/>
<result column="createtime" property="createtime"/>
<result column="state" property="state" />
</collection>
</resultMap>
<select id="selectByUserIdForOrder" resultMap="Userparent" parameterType="int">
SELECT <include refid="selectById"/>
FROM tb_user u JOIN tb_order o
ON u.ID = o.userid
WHERE u.id= #{uid}
</select>
与上面不同的是集合映射使用关键字collection
,并且返回类型不再使用type
而是使用ofType
来指定
前面题目一映射是使用的继承
,现在题目二映射是直接在父映射中
继续映射,并且没有使用方法
六、补充
id | 唯一标识符 |
type | 写返回的类的类名 |
<result/> | 对非主键的映射 |
<id/> | 对主键的映射 |
property | 关联属性名 也就是User类中定义的各属性 |
column | 关联属数据库的字段 |
javaType | 关联属性的数据类型 在集合属性时不要写,但是在题目一的情况下就需要使用 |
ofType | 关联属性的数据类型 在集合属性时写,但是在题目一的情况下就不要使用 |