(九)高级映射
目录
需求
关联查询:查询购买某些商品的用户信息 ;
主表:订单表 ;
关联表:用户表 ;
一对一映射(使用 resultType)
sql语句SELECT `order`.* ,`user`.`name` ,`user`.sex FROM `order`,`user` WHERE `user`.id = `order`.user_id ;创建
pojo对象将上面查询的结果列的所有信息,封装到该
pojo中 ;这与复杂查询创建pojo对象不一样,复杂查询创建pojo对象是为了,封装查询条件 ;这里我们是为了 封装查询结果 ;从查询的列中,可以看出结果来自
user、order表 ,我们在设计 pojo 对象的时候,选择让其继承包含列字段段多的类,这样,我们可以在pojo中少写一些属性;这里我选择继承字段多的
user类 ;/** *User增强类,封装最后的查询结果 *@author An */ public class UserCustomerMapper extends User { // 将 order 类的字段添加进来 private int order_id ; private int user_id ; public int getOrder_id() { return order_id; } public void setOrder_id(int order_id) { this.order_id = order_id; } public int getUser_id() { return user_id; } public void setUser_id(int user_id) { this.user_id = user_id; } }创建
映射关系文件<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="xin.ijava.dao.UserCustomerMapper"> <select id="findOrderUsers" resultType="xin.ijava.dao.UserCustomer"> SELECT `order`.* ,`user`.`name` ,`user`.sex FROM `order`,`user` WHERE `user`.id = `order`.user_id </select> </mapper>创建同名的接口
@SuppressWarnings("unused") public interface UserCustomerMapper { public List<UserCustomer> findOrderUsers() throws Exception ; }测试结果
可以看到,我们已经将结果中列的数据,都封装到 UserCustomer 类中了 ;
一对一映射(使用 resultMap)
我们发现前面我们在创建 pojo 对象,是选择继承包含结果集中列多的类,然后在 pojo 类添加新的属性 ;
我们发现,即使这样做,我们还是很反感,特别是不同表之间有重名的列,生成 get set 方法就会出问题, 为什么就不能直接添加一个包含那些属性的对象进去呢?
答案是可以的,使用 resultMap ;
创建 pojo 对象 ;
public class UserOrders extends User { // 直接传进来 order 对象 private Order order ; public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } }创建
resultMap<!--type :最后将结果映射到的对象类--> <resultMap id="findOrders" type="xin.ijava.dao.UserOrders"> <!--主对象,也就是被继承对象--> <id column="id" property="id"></id> <result column="name" property="name"/> <result column="sex" property="sex"/> <!--关联对象,也就是传进来的对象--> <!-- property : 关联对象在主对象中的引用名--> <association property="order" javaType="xin.ijava.pojo.Order"> <id column="order_id" property="order_id"/> <result column="user_id" property="user_id"/> </association> </resultMap>配置
sql<sql id="query_Orders_users"> SELECT `order`.* ,`user`.`name` ,`user`.sex FROM `order`,`user` WHERE `user`.id = `order`.user_id </sql> <select id="findOrdersUserResultMap" resultMap="findOrders"> <include refid="query_Orders_users"/> </select>创建接口方法
public List<UserOrders> findOrdersUserResultMap() throws Exception ;测试结果
可以看出来,结果也被我们封装进去了 ;
小结
可以看出,resultType 适用于将结果集中列的结果映射到对象的一次映射到对应的属性上(一对一 ) ;
而resultMap 则是用于,将结果中多列的内容,映射到一个对象中(一对多 ) ;
resultType 无法实现延迟加载,resultMap 可以实现延迟加载 ;
需求
查询 订单 及 订单明细
一对多映射
sql语句查询SELECT `order`.order_id, `user`.id , `user`.`name` , orderdetail.id orderDetailsId, orderdetail.number FROM `order`,`user`, orderdetail,items WHERE `user`.id = `order`.user_id AND orderdetail.item_id = items.id AND `order`.order_id = orderdetail.order_id ;查询结果:
备注:再进行多表查询的时候,分清主表,关联表(主表没有直接关联,就通过一系列的中间表进行关联) where 后面写主键关系,按照逻辑写下去;创建
pojo对象首先讲下 覆盖现象:
mybatis在往对象中,映射结果的时候,一条记录一条记录的映射 ;这里说下,我们在映射文件中规定主对象的
id是user的id,那么,mybatis就会根据user的id,来分辨是不是同一个对象 ,以便将信息映射到对象中;比如,第一条记录,创建出
pojo对象了,然后订单对象被赋值了,然后映射第二条记录,mybatis会去检查该条记录中的user的id,看是不是新对象,如果是,则创建新的pojo对象,如果是已经创建过的对象,则将结果映射到之前的pojo对象中,这样,假如pojo字段,设定的不正确,就会产生覆盖;从结果中我们看到,
张三拥有多个不同的订单号,因此,在pojo中,我们应该用集合存储订单对象,来避免覆盖 ;订单明细,也是一个对象,一个订单会产生多条订单明细记录,因为一个订单会购买多种不同的产品嘛 ,因此,也用集合存储;public class UserOrders extends User { private List<OrderDetails> orderDetails ; private List<Order> orders ; public List<OrderDetails> getOrderDetails() { return orderDetails; } public void setOrderDetails(List<OrderDetails> orderDetails) { this.orderDetails = orderDetails; } public List<Order> getOrders() { return orders; } public void setOrders(List<Order> orders) { this.orders = orders; } }创建
resultMap将结果信息封装到集合中,使用
collection;<!--封装订单信息到 UsersOrder 中 --> <!--extends 继承其他 map --> <resultMap id="findOrdersAndOrderDetailsMap" type="xin.ijava.dao.UserOrders" extends="findOrders"> <!--封装信息到 集合--> <!--ofType 封装对象的类型--> <!--property 封装对象的引用名字--> <collection property="orderDetails" ofType="xin.ijava.pojo.OrderDetails"> <result column="orderDetailsId" property="order_id"/> <result column="number" property="number"/> </collection> </resultMap>配置
sql<select id="findOrdersAndOrderDetails" resultMap="findOrdersAndOrderDetailsMap"> SELECT `order`.order_id, `user`.id , `user`.`name` , orderdetail.id orderDetailsId, orderdetail.number FROM `order`,`user`, orderdetail,items WHERE `user`.id = `order`.user_id AND orderdetail.item_id = items.id AND `order`.order_id = orderdetail.order_id </select>编写接口方法
public List<UserOrders> findOrdersAndOrderDetails() throws Exception ;测试结果
我们可以发现,在数据库查询出来的 4 条记录,在这里被封装成 2 个对象了 ,完全符合我们的期望,因为,我们创建的 pojo 对象,是按照用户为主体的,上面的 4 条记录,是 2 个用户产生的,因此,最后也被封装到 2 个对象中 ;
小结
resultMap 主要是根据我们告诉它的 id ,也就是对象的唯一标识符号,来确定是不是同一个对象的 ;
需求
查询所有 用户 购买的具体商品,将它们封装到一个集合中 ;
如果是:查询某一个具体 用户 购买的具体商品,将它们封装到一个集合中,这样打印账单的活,则没有必要使用 resultMap 了 ;
主表: user
关联表 :items
多对多映射
sql语句SELECT `user`.id user_id, `user`.`name` user_name, `user`.address user_address, `order`.order_id , `order`.createtime create_time, items.id item_id, items.`name` item_name, orderdetail.number item_number FROM `user`,`order`,orderdetail,items WHERE `user`.id = `order`.user_id AND `order`.order_id = orderdetail.order_id AND items.id = orderdetail.item_id ;创建
resultMap<resultMap id="findUserAndItemsMap" type="xin.ijava.pojo.UserItems"> <id column="user_id" property="id"/> <result column="user_name" property="name"/> <result column="user_address" property="address"/> <collection property="orders" ofType="xin.ijava.pojo.Order"> <id column="order_id" property="order_id"/> <result column="create_time" property="createTime"/> <!--嵌套 collection --> <collection property="orderDetails" ofType="xin.ijava.pojo.OrderDetails"> <id column="order_id" property="order_id"/> <result column="item_number" property="number"/> <result column="item_number" property="number"/> <!--关联对象--> <association property="item" javaType="xin.ijava.pojo.Items"> <id column="item_id" property="id"/> <result column="item_name" property="name"/> </association> </collection> </collection> </resultMap>跟俄罗斯套娃一样,一层套一层,我们使用
collection、association完成数据的嵌套 ;配置
sql<select id="findUserAndItems" resultMap="findUserAndItemsMap"> SELECT `user`.id user_id, `user`.`name` user_name, `user`.address user_address, `order`.order_id , `order`.createtime create_time, items.id item_id, items.`name` item_name, orderdetail.number item_number FROM `user`,`order`,orderdetail,items WHERE `user`.id = `order`.user_id AND `order`.order_id = orderdetail.order_id AND items.id = orderdetail.item_id </select>编写接口方法
public List<UserItems> findUserAndItems() throws Exception ;测试结果
总结
选择 resultType 还是选择 resultMap 看需求 ;
比如上面实现的商品明细,假如有特殊要求,将它们映射到一个集合中,那么则选用 resultMap ;如果只是想打印账单那样,那么使用 resultType ;主要是看最后对映射结果的要求 ;

浙公网安备 33010602011771号