深入浅出Mybatis(八)高级映射
2018-03-31 18:37
465 查看
前面的章节使用的都是对单张表的操作,但是在实际开发当中,很多时候需要关联多张表,这时就需要用到我们的高级映射,包括一对一,一对多和多对多。
下面先来分析一个简单的业务场景。
有四张表:
用户表:user保存用户相关信息。CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL COMMENT '用户名',
`birthday` date DEFAULT NULL COMMENT '出生年月',
`sex` varchar(255) DEFAULT NULL COMMENT '性别',
`addr` varchar(255) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;添加测试数据:
商品表:items保存商品相关的信息。CREATE TABLE `items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`price` decimal(10,2) NOT NULL,
`detail` varchar(255) DEFAULT NULL,
`pic` varchar(255) DEFAULT NULL,
`createtime` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;添加测试数据:
订单表:orders保存订单的信息,关联用户表user,一个订单对应一个user用户。CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单号',
`user_id` int(11) NOT NULL,
`number` int(32) NOT NULL,
`createtime` datetime NOT NULL,
`note` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;添加测试数据:
订单明细表:orderdetail一个订单当中包含多个商品。CREATE TABLE `orderdetail` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`orders_id` int(11) NOT NULL,
`items_id` int(11) NOT NULL,
`items_num` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `orders_id` (`orders_id`),
KEY `items_id` (`items_id`),
CONSTRAINT `orderdetail_ibfk_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`),
CONSTRAINT `orderdetail_ibfk_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;添加测试数据:
4000
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}sql语句
List<OrdersCustom> findOrdersUser() throws Exception;测试:
<!-- 查询订单关联查询用户,使用resultMap -->
<select id="findOrdersUserResultMap" resultMap="ordersUserResultMap">
select orders.*,user.username,user.sex,user.addr from orders,user WHERE orders.user_id=user.id
</select>
如果没有查询结果的特殊要求,建议使用resultType。
resultMap:需要单独定义resultMap,实现有点麻烦,如果有对查询结果的特殊要求,使用resultMap可完成将
关联查询映射到pojo属性中。
resultMap可以实现延迟加载,resultType不能实现延迟加载。
关联表:orderdetail
sql语句:<!-- 查询订单关联查询用户及订单明细,使用resultMap -->
<select id="findOrdersAndOrderDetailResultMap" resultMap="ordersAndOrderDetailResultMap">
select
orders.*,
user.username,
user.sex,
user.addr,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id
from
orders,
user,
orderdetail
where
orders.user_id=user.id
and
orders.id=orderdetail.orders_id
</select>
然后需在orders类中添加一个orderDetails属性,并生成get和set方法。定义resultMap:
由于前面定义了订单及用户的信息,这里可以直接继承;<!-- 查询订单及订单明细的resultMap -->
<resultMap id="ordersAndOrderDetailResultMap" type="orders" extends="ordersUserResultMap">
<!-- 订单信息,通过继承得到 -->
<!-- 用户信息,通过继承得到 -->
<!-- 订单明细信息
collection:对关联查询的到的多条记录映射到集合中
property:orders中要映射的哪个属性
ofType:集合属性中pojo的类型
-->
<collection property="orderDetails" ofType="com.beyond.mybatis.po.OrderDetail">
<!-- 主键 -->
<id column="orderdetail_id" property="id"/>
<!--普通列-->
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="orderId"/>
</collection>
</resultMap>添加接口方法:
思路:在user中添加订单列表的属性,List<Orders> orders
在orders中添加订单明细列表的属性,List<OrderDetail> orderDetails;
在orderDetail中添加商品属性,Items items,
sql语句:<!-- 查询用户及用户购买的商品信息,使用resultMap -->
<select id="findUsersAndItemsResultMap" resultMap="usersAndItemsResultMap">
select
orders.*,
user.username,
user.sex,
user.addr,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id,
items.name items_name,
items.detail items_detail,
items.price items_price
from
orders,
user,
orderdetail,
items
where
orders.user_id=user.id
and
orders.id=orderdetail.orders_id
and
orderdetail.items_id=items.id
</select>User类中添加:private List<Orders> orders;生成get和set方法。
<!-- 查询用户及用户所购买的商品信息 -->
<resultMap id="usersAndItemsResultMap" type="user">
<!-- 用户信息 -->
<id column="user_id" property="userId"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="addr" property="addr"/>
<!-- 一个用户对应多个订单信息 -->
<collection property="orders" ofType="com.beyond.mybatis.po.Orders">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!-- 一个订单对应多个订单明细信息 -->
<collection property="orderDetails" ofType="com.beyond.mybatis.po.OrderDetail">
<!-- 主键 -->
<id column="orderdetail_id" property="id"/>
<!--普通列-->
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="orderId"/>
<!-- 一个订单明细对应一条商品信息 -->
<association property="items" javaType="com.beyond.mybatis.po.Items">
<id column="items_id" property="id"/>
<result column="items_name" property="name"/>
<result column="items_detail" property="detail"/>
<result column="items_price" property="price"/>
</association>
</collection>
</collection>
</resultMap>编写接口方法://查询用户及用户购买的商品信息
List<User> findUsersAndItemsResultMap() throws Exception;测试: @Test
public void testfindUsersAndItemsResultMap() throws Exception{
SqlSession sqlSession = factory.openSession();
//通过反射拿到UserMapper的代理对象
OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class);
List<User> list = ordersMapperCustom.findUsersAndItemsResultMap();
System.out.println(list);
}断点调试查看list的信息:
一共有两个用户有订单,
一个用户购买了三件商品:华硕、联想和神州
另外一个用户购买了两件商品:华硕和苹果
下面先来分析一个简单的业务场景。
有四张表:
用户表:user保存用户相关信息。CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL COMMENT '用户名',
`birthday` date DEFAULT NULL COMMENT '出生年月',
`sex` varchar(255) DEFAULT NULL COMMENT '性别',
`addr` varchar(255) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;添加测试数据:
商品表:items保存商品相关的信息。CREATE TABLE `items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`price` decimal(10,2) NOT NULL,
`detail` varchar(255) DEFAULT NULL,
`pic` varchar(255) DEFAULT NULL,
`createtime` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;添加测试数据:
订单表:orders保存订单的信息,关联用户表user,一个订单对应一个user用户。CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单号',
`user_id` int(11) NOT NULL,
`number` int(32) NOT NULL,
`createtime` datetime NOT NULL,
`note` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;添加测试数据:
订单明细表:orderdetail一个订单当中包含多个商品。CREATE TABLE `orderdetail` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`orders_id` int(11) NOT NULL,
`items_id` int(11) NOT NULL,
`items_num` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `orders_id` (`orders_id`),
KEY `items_id` (`items_id`),
CONSTRAINT `orderdetail_ibfk_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`),
CONSTRAINT `orderdetail_ibfk_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;添加测试数据:
第一个需求,查询订单并关联用户的信息。
创建orders类,public class Orders {4000
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}sql语句
select orders.*,user.username,user.sex,user.addr from orders,user WHERE orders.user_id=user.id
1:使用resultType作映射。
<!-- 查询订单关联查询用户 --> <select id="findOrdersUser" resultType="OrdersCustom"> select orders.*,user.username,user.sex,user.addr from orders,user WHERE orders.user_id=user.id </select>由于orders类中没有用户的相关信息,所以这里需要使用一个扩展类继承orders,并添加用户的属性。
/** * @author:kevin * @description: 订单的扩展类 * 通过此类映射订单和用户查询的结果,让此类继承包括字段较多的pojo类 * @create 2018-03-31 9:40 */ public class OrdersCustom extends Orders{ //添加属性 private String username; private String sex; private String addr; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; } }在当前包下新建一个接口OrdersMapperCustom和xml OrdersMapperCustom.xml
将xml中的namespace改成接口的路径
com.beyond.mybatis.mapper.OrdersMapperCustom
<!-- 查询订单关联查询用户 --> <select id="findOrdersUser" resultType="OrdersCustom"> select orders.*,user.username,user.sex,user.addr from orders,user WHERE orders.user_id=user.id </select>在接口中添加对应的方法。//查询订单关联查询用户信息
List<OrdersCustom> findOrdersUser() throws Exception;测试:
@Test public void testfindOrdersUser() throws Exception{ SqlSession sqlSession = factory.openSession(); //通过反射拿到UserMapper的代理对象 OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class); List<OrdersCustom> list = ordersMapperCustom.findOrdersUser(); System.out.println(list); }通过断点调试,查看list中的值:
查询到了三条记录:
2:使用resultMap进行映射
在orders类中添加一个属性User。<!-- 查询订单关联查询用户,使用resultMap -->
<select id="findOrdersUserResultMap" resultMap="ordersUserResultMap">
select orders.*,user.username,user.sex,user.addr from orders,user WHERE orders.user_id=user.id
</select>
<!-- 订单查询关联用户的resultMap --> <resultMap id="ordersUserResultMap" type="Orders"> <!-- 配置映射的订单信息 --> <!-- id:指定查询列中的唯一标识,如果多个列组成唯一标识,配置多个id --> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="number" property="number"/> <result column="createtime" property="createtime"/> <result column="note" property="note"/> <!-- 配置映射的关联的用户信息 --> <!-- association:用于映射关联查询单个对象的信息 property:要将关联查询的用户信息映射到Orders中的哪个属性 --> <association property="user" javaType="com.beyond.mybatis.po.User"> <!-- id:关联查询用户的唯一标识 column:指定唯一标识用户信息的列 javaType:映射到user的哪个属性 --> <id column="user_id" property="id"/> <result column="username" property="username"/> <result column="sex" property="sex"/> <result column="addr" property="addr"/> </association> </resultMap>
//查询订单关联查询用户信息,resultMap List<Orders> findOrdersUserResultMap() throws Exception;
测试:
@Test public void testfindOrdersUser() throws Exception{ SqlSession sqlSession = factory.openSession(); //通过反射拿到UserMapper的代理对象 OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class); List<Orders> list = ordersMapperCustom.findOrdersUserResultMap(); System.out.println(list); }对其进行断点调试:
实现一对一查询时的resultType和resultMap的小结:
resultType:使用非常简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射,如果没有查询结果的特殊要求,建议使用resultType。
resultMap:需要单独定义resultMap,实现有点麻烦,如果有对查询结果的特殊要求,使用resultMap可完成将
关联查询映射到pojo属性中。
resultMap可以实现延迟加载,resultType不能实现延迟加载。
第二个需求,查询订单及订单明细,一对多的查询
主表:orders关联表:orderdetail
sql语句:<!-- 查询订单关联查询用户及订单明细,使用resultMap -->
<select id="findOrdersAndOrderDetailResultMap" resultMap="ordersAndOrderDetailResultMap">
select
orders.*,
user.username,
user.sex,
user.addr,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id
from
orders,
user,
orderdetail
where
orders.user_id=user.id
and
orders.id=orderdetail.orders_id
</select>
然后需在orders类中添加一个orderDetails属性,并生成get和set方法。定义resultMap:
由于前面定义了订单及用户的信息,这里可以直接继承;<!-- 查询订单及订单明细的resultMap -->
<resultMap id="ordersAndOrderDetailResultMap" type="orders" extends="ordersUserResultMap">
<!-- 订单信息,通过继承得到 -->
<!-- 用户信息,通过继承得到 -->
<!-- 订单明细信息
collection:对关联查询的到的多条记录映射到集合中
property:orders中要映射的哪个属性
ofType:集合属性中pojo的类型
-->
<collection property="orderDetails" ofType="com.beyond.mybatis.po.OrderDetail">
<!-- 主键 -->
<id column="orderdetail_id" property="id"/>
<!--普通列-->
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="orderId"/>
</collection>
</resultMap>添加接口方法:
//查询订单关联查询订单明细信息 List<Orders> findOrdersAndOrderDetailResultMap() throws Exception;测试:
@Test public void testfindOrdersAndOrderDetailResultMap() throws Exception{ SqlSession sqlSession = factory.openSession(); //通过反射拿到UserMapper的代理对象 OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class); List<Orders> list = ordersMapperCustom.findOrdersAndOrderDetailResultMap(); System.out.println(list); }利用断点调试,观察list集合。
一共有两个订单,第一个订单属于id为的用户,且包含三个订单明细(即包含三件商品)。
第三个需求,查询用户及用户购买的商品,多对多
主表:user思路:在user中添加订单列表的属性,List<Orders> orders
在orders中添加订单明细列表的属性,List<OrderDetail> orderDetails;
在orderDetail中添加商品属性,Items items,
sql语句:<!-- 查询用户及用户购买的商品信息,使用resultMap -->
<select id="findUsersAndItemsResultMap" resultMap="usersAndItemsResultMap">
select
orders.*,
user.username,
user.sex,
user.addr,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id,
items.name items_name,
items.detail items_detail,
items.price items_price
from
orders,
user,
orderdetail,
items
where
orders.user_id=user.id
and
orders.id=orderdetail.orders_id
and
orderdetail.items_id=items.id
</select>User类中添加:private List<Orders> orders;生成get和set方法。
Orders类中在上面已经添加,Orders类中在上面已经添加,在OrderDetail中添加Items属性同样生成get和set方法。 编写resultMap:
<!-- 查询用户及用户所购买的商品信息 -->
<resultMap id="usersAndItemsResultMap" type="user">
<!-- 用户信息 -->
<id column="user_id" property="userId"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="addr" property="addr"/>
<!-- 一个用户对应多个订单信息 -->
<collection property="orders" ofType="com.beyond.mybatis.po.Orders">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!-- 一个订单对应多个订单明细信息 -->
<collection property="orderDetails" ofType="com.beyond.mybatis.po.OrderDetail">
<!-- 主键 -->
<id column="orderdetail_id" property="id"/>
<!--普通列-->
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="orderId"/>
<!-- 一个订单明细对应一条商品信息 -->
<association property="items" javaType="com.beyond.mybatis.po.Items">
<id column="items_id" property="id"/>
<result column="items_name" property="name"/>
<result column="items_detail" property="detail"/>
<result column="items_price" property="price"/>
</association>
</collection>
</collection>
</resultMap>编写接口方法://查询用户及用户购买的商品信息
List<User> findUsersAndItemsResultMap() throws Exception;测试: @Test
public void testfindUsersAndItemsResultMap() throws Exception{
SqlSession sqlSession = factory.openSession();
//通过反射拿到UserMapper的代理对象
OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class);
List<User> list = ordersMapperCustom.findUsersAndItemsResultMap();
System.out.println(list);
}断点调试查看list的信息:
一共有两个用户有订单,
一个用户购买了三件商品:华硕、联想和神州
另外一个用户购买了两件商品:华硕和苹果
相关文章推荐
- 深入浅出Mybatis系列(七)---mapper映射文件配置之insert、update、delete
- MyBatis之高级关联和集合映射(二、嵌套结果综合案例)
- Mybatis 高级结果映射 ResultMap Association Collection
- 深入浅出Mybatis系列(七)---mapper映射文件配置之insert、update、delete
- MyBatis 入门到精通(三) 高级结果映射
- Mybatis学习(08)-高级映射之一对多查询
- mybatis入门基础(六)----高级映射(一对一,一对多,多对多)
- MyBatis高级结果映射集ResultMap
- 【mybatis基础】高级映射:一对一查询
- Mybatis 高级结果映射 ResultMap Association Collection
- MyBatis高级映射:一对一
- mybatis高级映射
- mybatis高级映射
- 深入浅出Mybatis系列(八)---mapper映射文件配置之select、resultMap
- 【Mybatis】---高级映射之一对一查询
- MyBatis-高级映射:多对多
- 框架学习系列 mybatis 第十八篇 高级结果一对一结果映射之resultMap的使用
- mybatis-高级结果映射之一对多(你知道一对多的结果是如何合并的吗)
- mybatis 高级映射和spring整合之与Spring整合(6)
- MyBatis入门第3天--高级映射与查询缓存