MyBatis系列(四 )——MyBatis的多表操作
前言
在前面的系列文章学习中,我们已经可以实现对单表进行CRUD等操作了,但是对于多表操作来说,返回的结果往往是多表查询后的数据集,这个时候我们又应该如何去封装我们的结果集呢?本篇文章将针对MyBatis的多表操作的使用进行介绍,希望能够对各位读者一个参考。
想要了解更多MyBaits系列文章,可以从下面的传送门阅读:
MyBatis系列(一)——MyBatis的介绍和CRUD
MyBatis系列(二)——MyBatis的动态代理和映射文件动态配置
MyBatis系列(三)——MyBatis的类型处理器和PageHelper分页插件
一、表和表之间的关系
在讲MyBatis
的多表操作之前,我们不妨先回顾一下,在关系型数据库中,表和表之间的关系都有哪些。
(一)一对一关系
比如存在订单表和用户表,订单表对于用户表而言就是一对一的关系,因为一个订单只能对应一个用户,订单表中使用userId
作为外键关联用户user
表
(二)一对多关系
一对多的关系在生活中也很好找例子,一个班级可以有很多个学生,一个用户可以有很多订单,用户user
通过userId
可以关联到多张订单表。
(三)多对多关系
一个学生可以选多门课程,一门课程也可以被多个学生选择,这就是生活中的多对多关系。再比如一个用户可以有多个角色,一个角色也可以被分配给多个用户。在实际操作中,我们往往会使用一张中间表来保存二者之间的关联关系。
二、使用MyBatis进行多表操作
我们从之前的文章学习中知道,在单表操作中,MyBaits
是给我们提供了resultType
属性让我们选择封装的对象,但是使用多表查询操作中,结果集中势必会有多张表的字段交互的结果。这个时候,单纯的resultType
已经是不能够满足我们承载结果集的数据了,这就引出了resultMap
属性。
(一)一对一操作
我们以订单的例子来进行演示,一个订单对应一个用户。
步骤一:创建POJO类,用户和订单类简要代码如下:
public class Order {
private Integer oid;
private Date createtime;
private Double total;
// 一个订单对应一个用户,所以这里不写userId,而是用User这个完整对象
private User user;
}
public class User {
private Integer uid;
private String username;
private String password;
private Date birth;
}
步骤二:创建OrderMapper.xml
映射文件
这里需要注意,对于Order对象中的User属性,我们可以使用类似于user属性名.属性
的方式来选择注入结果集的数据。
<mapper namespace="com.qiqv.dao.OrderMapper">
<resultMap id="orderMap" type="com.qiqv.pojo.Order">
<!--手动指定字段与实体属性的映射关系 column: 数据表的字段名称 property:实体的属性名称 -->
<id column="oid" property="oid"></id>
<result column="createtime" property="createtime"></result>
<result column="total" property="total"></result>
<result column="uid" property="user.uid"></result>
<result column="username" property="user.username"></result>
<result column="password" property="user.password"></result>
<result column="birth" property="user.birth"></result>
</resultMap>
<select id="getOrderById" parameterType="int" resultMap="orderMap">
select * from orders o,user u where o.oid = u.uid and oid = #{id}
</select>
</mapper>
除了上面这种方式外,我们还可以使用association
标签来封装Order
对象中的User
属性
<resultMap id="orderMap" type="com.qiqv.pojo.Order">
<!--手动指定字段与实体属性的映射关系 column: 数据表的字段名称 property:实体的属性名称 -->
<id column="oid" property="oid"></id>
<result column="createtime" property="createtime"></result>
<result column="total" property="total"></result>
<association property="user" javaType="user">
<id column="uid" property="uid"></id>
<result column="username" property="username"></result>
<result column="password" property="password"></result>
<result column="birth" property="birth"></result>
</association>
</resultMap>
步骤三:在核心配置文件中引入映射文件和配置别名
<!-- 配置别名 -->
<typeAliases >
<typeAlias type="com.qiqv.pojo.User" alias="user"></typeAlias>
<typeAlias type="com.qiqv.pojo.Order" alias="order"></typeAlias>
</typeAliases>
<mappers>
<mapper resource="com/qiqv/mapper/UserMapper.xml"></mapper>
<mapper resource="com/qiqv/mapper/OrderMapper.xml"></mapper>
</mappers>
步骤四:在Mapper接口文件中加入方法
public interface OrderMapper {
// 根据oid查询订单信息
Order getOrderById(Integer oid);
}
步骤五:在代码中进行测试
@Test
public void getOrderByIdTest() throws Exception{
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
System.out.println(mapper.getOrderById(1));
}
(二)一对多操作
一对多的表关系,我们在第一节就已经介绍过了。比如一个用户有多个订单,可以联想到要想实现查询用户的时候顺带查询订单,就需要在原有的用户类基础上新增一个封装有订单的List
集合。
步骤一:修改原有的User
对象
public class User {
private Integer uid;
private String username;
private String password;
private Date birth;
private List<Order> orders;
}
步骤二:在映射文件中新增对应的查询语句和resultMap
配置
<resultMap id="userOMap" type="com.qiqv.pojo.User">
<id column="uid" property="uid"></id>
<result column="username" property="username"></result>
<result column="birth" property="password"></result>
<!--
使用collection标签来封装List集合对象
property 表示属性名称 ofType 表示集合中封装的对象类型
-->
<collection property="orders" ofType="com.qiqv.pojo.Order">
<id column="oid" property="oid"></id>
<result column="createtime" property="createtime"></result>
<result column="total" property="total"></result>
</collection>
</resultMap>
<select id="getAllUserOrderByUid" parameterType="int" resultMap="userOMap">
select * from user u ,orders o where u.uid = o.uid and u.uid = #{id}
</select>
步骤三:在核心配置文件配置别名和映射文件(如果之前已经做了就可以忽略这一步)
<!-- 配置别名 -->
<typeAliases >
<typeAlias type="com.qiqv.pojo.User" alias="user"></typeAlias>
<typeAlias type="com.qiqv.pojo.Order" alias="order"></typeAlias>
</typeAliases>
<mappers>
<mapper resource="com/qiqv/mapper/UserMapper.xml"></mapper>
<mapper resource="com/qiqv/mapper/OrderMapper.xml"></mapper>
</mappers>
步骤四:在Mapper接口文件中加入方法
public interface UserMapper {
// 查询用户的订单方法
User getAllUserOrderByUid(Integer uid) throws Exception;
}
步骤五:在测试中进行测试
@Test
public void getAllUserOrderByUidTest() throws Exception{
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
System.out.println(mapper.getAllUserOrderByUid(1));
}
(三)多对多操作
多对多本质上其实就是两个一对多关系,只要理解了一对多的写法,多对多其实并没有什么不同。在本小节中,我们会举例用户和角色之间的多对多关系进行演示操作。
步骤一:创建实体类对象
public class User {
private Integer uid;
private String username;
private String password;
private Date birth;
private List<Order> orders;
private List<Role> roles;
}
public class Role {
private int id;
private String rolename;
}
步骤二:定义映射文件方法内容:
<resultMap id="userRoleMap" type="user">
<id column="uid" property="uid"></id>
<result column="username" property="username"></result>
<result column="password" property="password"></result>
<result column="birth" property="password"></result>
<collection property="roles" ofType="role">
<id column="rid" property="id"></id>
<result column="rolename" property="rolename"></result>
</collection>
</resultMap>
<select id="getAllUserRoleByUid" parameterType="int" resultMap="userRoleMap">
select * from user u left join user_role_table ur on u.uid=ur.uid left join roles r on ur.rid = r.id where u.uid = 1
</select>
步骤三:在核心配置文件中配置别名和映射文件(如果已经加过了就忽略这一步)
<!-- 配置别名 -->
<typeAliases >
<typeAlias type="com.qiqv.pojo.User" alias="user"></typeAlias>
<typeAlias type="com.qiqv.pojo.Role" alias="role"></typeAlias>
</typeAliases>
<mappers>
<mapper resource="com/qiqv/mapper/UserMapper.xml"></mapper>
</mappers>
步骤四:在mapper接口中添加方法
public interface UserMapper {
// 根据uid查询用户和所属角色
User getAllUserRoleByUid(Integer uid);
}
步骤五:在代码中进行测试
@Test
public void getAllUserRoleByUidTest() throws Exception {
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getAllUserRoleByUid(1);
for(Role role : user.getRoles()){
System.out.println(role);
}
}
说在最后
至此,有关MyBatis的多表操作就讲解结束了,其实MyBatis的多表操作实现并不复杂,关键在于知道resultMap
的使用,我们通过resultMap
封装好POJO类中的结果集后,其他的自然没有难度。另外需要注意的是多对多的表关系,本质上只是两个对象之间的一对多,用的时候需要注意不要写漏了即可。