引言
在实际开发中,对数据库的操作常常会涉及到多张表,针对多表之间的操作,MyBatis 提供了关联映射,通过关联映射可以很好地处理表与表、对象与对象之间的关联关系。在关系型数据库中,表与表之间存在着三种关联映射关系,分别为一对一关系、一对多关系和多对多关系。
一、关系映射的概述
在 MyBatis 中,通过 association 元素来处理对象与对象之间关联关系,association 元素提供了一系列属性用于维护数据表之间的关系。association 元素是 resultMap元素的子元素,它有两种配置方式,嵌套查询方式和嵌套结果集方式。
属性 | 说明 |
column | 表示数据库中的列名,对应实体类中的属性名。 |
property | 表示实体类中的属性名,对应数据库中的列名。 |
collection | 表示集合类型,对应实体类中的List、Set等集合类型 |
ofType | 表示集合中元素的类型,用于指定集合中元素的类型。 |
association | 表示一对一关联关系,对应实体类中的一个属性和一个数据库表中的一列。 |
javaType | 表示Java中的数据类型,用于指定集合中元素的类型。 |
二、resultType与resultMap区别
这里我们假设一个场景,我们在开发项目的时候编写代码用的是嵌套结果集的方式,我们用的是resultType(resultType="com.csdn.xw.model.Book"),这个时候客户的需求是查出书籍名字和书籍价格,等你写完需求后面客户又变需求了,你为了方便写成resultType="java.util.Map",这时候不论客户什么时候该需求,我们的这串代码都不会变。时过境迁,你离开了原来的公司,后面来的开发者,看你写的代码并不会知道,你所接收的字段有什么,是书籍名字还是书籍名称和书籍价格等等,这就是不足之处。
通过上面的小故事我们总结一下:
使用 resultType,我们直接指定了查询结果的类型(这里是 "com.csdn.xw.model.Book"),它通常用于简单的查询语句,不需要复杂的映射关系。优点是简单直观,缺点是不能进行复杂的映射操作(实体类没有该属性的情况)。
而使用 resultMap,我们可以更加灵活地映射查询结果到任意类型的 Java 对象上。通过定义一个 resultMap,我们可以指定每个查询结果列与 Java 对象属性之间的映射关系。优点是功能强大,可以进行各种复杂的映射操作,缺点是需要编写更多的 XML 配置代码。
下面以嵌套结果集进行演示表与表之间存在着三种关联映射关系。
三、一对一关系查询
这里需要建一个VO类,VO是Value Object的缩写,是一种轻量级的数据结构,用于在视图层与业务逻辑层之间传递数据。VO通常用于表示视图层所需的数据,这些数据来自于业务逻辑层或数据访问层。VO的主要目的是将业务逻辑层的数据结构转换为视图层可以使用的数据结构 。简单来说就是用于关系映射时的结果接收。
下面我们利用订单项以及订单来描述一对一的关系,所以我们建立一个OrderitemVo。
public class OrderitemVo extends Orderitem { private Order order; public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; }
3.1.嵌套结果集编写
<resultMap id="OrderitemvoMap" type="com.csdn.xw.vo.OrderitemVo"> <result column="order_item_id" property="orderItemId"></result> <result column="product_id" property="productId"></result> <result column="quantity" property="quantity"></result> <result column="oid" property="oid"></result> <association property="order" javaType="com.csdn.xw.model.Order"> <result column="order_id" property="orderId"></result> <result column="order_no" property="orderNo"></result> </association> </resultMap> <select id="selectByOiid" resultMap="OrderitemvoMap" parameterType="java.lang.Integer"> select * from t_hibernate_order o,t_hibernate_order_item oi where o.order_id=oi.oid and oi.order_item_id=#{oiid} </select>
3.2.案例测试
Biz编写
public interface OrderitemBiz { OrderitemVo selectByOiid(Integer oiid); }
Impl编写
@Service public class OrderitemImpl implements OrderitemBiz { @Autowired private OrderitemMapper OrderitemMapper; @Override public OrderitemVo selectByOiid(Integer oiid) { return OrderitemMapper.selectByOiid(oiid); } }
Test测试
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:spring-context.xml"}) public class OrderitemImplTest { @Autowired private OrderitemBiz OrderitemBiz; @Test public void selectByOiid() { OrderitemVo orderitemVo = OrderitemBiz.selectByOiid(27); System.out.println(orderitemVo); System.out.println(orderitemVo.getOrder()); } }
测试结果:
四、一对多关系查询
下面我们利用订单以及订单项来描述一对多的关系,所以我们建立一个OrderVo。
public class OrderVo extends Order { private List<Orderitem> orderitems=new ArrayList<>(); public List<Orderitem> getOrderitems() { return orderitems; } public void setOrderitems(List<Orderitem> orderitems) { this.orderitems = orderitems; } @Override public String toString() { return "OrderVo{" + "orderitems=" + orderitems + '}'; } }
4.1.嵌套结果集编写
<resultMap id="OrderMap" type="com.csdn.xw.vo.OrderVo" > <result column="order_id" property="orderId"></result> <result column="order_no" property="orderNo"></result> <collection property="orderitems" ofType="com.csdn.xw.model.Orderitem"> <result column="order_item_id" property="orderItemId"></result> <result column="product_id" property="productId"></result> <result column="quantity" property="quantity"></result> <result column="oid" property="oid"></result> </collection> </resultMap> <select id="byOid" resultMap="OrderMap" parameterType="java.lang.Integer" > select * from t_hibernate_order o,t_hibernate_order_item oi where o.order_id=oi.oid and o.order_id=#{oid} </select>
4.2.案例测试
Biz编写
public interface OrderBiz { OrderVo byOid(Integer id); }
Impl编写
@Service public class OrderBizImpl implements OrderBiz { @Autowired private OrderMapper orderMapper; @Override public OrderVo byOid(Integer id) { return orderMapper.byOid(id); } }
Test编写
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:spring-context.xml"}) public class OrderBizImplTest { @Autowired private OrderBiz orderBiz; @Test public void byOid() { OrderVo orderVo = orderBiz.byOid(7); System.out.println(orderVo); orderVo.getOrderitems().forEach(System.out::println); } }
测试结果:
五、多对多关系查询
我们以书籍有多个类别以及每个类别又有多本书的这种关系来实操多对多关系的查询
HbookVo
public class HbookVo extends HBook { private List<HCategory> hcategory; public List<HCategory> getHcategory() { return hcategory; } public void setHcategory(List<HCategory> hcategory) { this.hcategory = hcategory; } }
5.1.嵌套结果集编写
<resultMap id="HbookVo" type="com.csdn.xw.vo.HbookVo" > <result column="book_id" property="bookId"></result> <result column="book_name" property="bookName"></result> <result column="price" property="price"></result> <collection property="hcategory" ofType="com.csdn.xw.model.HCategory"> <result column="category_id" property="categoryId"></result> <result column="category_name" property="categoryName"></result> </collection> </resultMap> <select id="selectByBid" resultMap="HbookVo" parameterType="java.lang.Integer"> SELECT * FROM t_hibernate_book b, t_hibernate_book_category bc, t_hibernate_category c WHERE b.book_id = bc.bid AND bc.cid = c.category_id AND b.book_id =#{bid} </select>
5.1.案例测试
Biz编写
public interface HBookBiz { HbookVo selectByBid(Integer bid); }
Impl编写
@Service public class HBookBizImpl implements HBookBiz { @Autowired private HBookMapper hbookMapper; @Override public HbookVo selectByBid(Integer bid) { return hbookMapper.selectByBid(bid); } }
Test编写
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:spring-context.xml"}) public class HBookBizImplTest { @Autowired private HBookBiz hbookBiz; @Test public void selectByBid() { HbookVo hbookVo = hbookBiz.selectByBid(8); System.out.println(hbookVo); hbookVo.getHcategory().forEach(System.out::println); } }
测试结果:
六、总结
resultMap和resultType的区别在于,resultType是直接表示返回类型(基础类型、包装类型),而resultMap则是对外部ResultMap的引用。
Vo和Dto是两种不同的数据传输对象。Vo主要用于显示层与业务层之间的数据传递,而Dto主要用于远程调用时不同层之间的数据传递。
ofType和javaType都是MyBatis中的类型处理器,用于处理Java类型和JDBC类型之间的转换。其中,ofType用于处理集合类型,而javaType用于处理基本数据类型和JDBC类型。
使用场景:当查询结果为集合类型时,可以使用ofType;当查询结果为基本数据类型或JDBC类型时,可以使用javaType。
到这里我的分享就结束了,欢迎到评论区探讨交流!!
如果觉得有用的话还请点个赞吧 ♥ ♥