前言:
今天我们来学习Mybatis的关联关系映射以及自定义resultMap三种映射关系,希望这篇博客可以帮助大家的学习工作!!!
经典面试题:
问 :在Mybatis中的表之间的关系是如何映射处理的?
答:
在MyBatis中,表与表之间的关系主要通过两种方式进行映射:一对一(One-to-One)和一对多(One-to-Many)关系。
对于一对一关系,可以使用两个表之间的外键进行映射。在MyBatis的映射文件中,可以使用<resultMap>标签定义一个结果映射对象,并使用<association>标签进行关联映射。
对于一对多关系,可以使用一个表的外键与另一个表的主键进行映射。在MyBatis的映射文件中,可以使用<resultMap>标签定义一个结果映射对象,并使用<collection>标签进行集合映射。
需要注意的是,在映射文件中,可以使用<resultMap>标签来定义表字段与Java对象属性之间的映射关系。
准备:将具有一对一,一对多的表导入mysqll数据库中去。
一,关联关系映射
关联关系映射在Mybatis中主要通过三种方式实现:一对一关联和一对多关联及多对多关联。
一,一对一
例如:一个用户(User)与一个地址(Address)之间的关系。
二,一对多
例如: 订单表的id对应多个订单详情表
三,多对多
例如:一本书对应多种类型,一种类型对应多本书
二,具体步骤:
一,一对一
2.1创建名为 t_hibernate_book (书籍表) 数据表
创建名为 t_hibernate_book_category (书籍类别表) 数据表
其中名为 bid 的属性字段为 t_hibernate_book (书籍表) 的 bid(主键) 的外键
其中名为 cid 的属性字段为 t_hibernate_category (类别表) 的 category_id (主键) 的外键
创建名为 t_hibernate_category (类别表) 数据表
t_hibernate_order (订单表) 数据表
t_hibernate_order_item (订单详情表) 数据表
修改 generatorConfig.xml 的配置文件
代码:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" > <generatorConfiguration> <!-- 引入配置文件 --> <properties resource="jdbc.properties"/> <!--指定数据库jdbc驱动jar包的位置--> <classPathEntry location="D:\\temp\\mvn_repository\\mysql\\mysql-connector-java\\5.1.44\\mysql-connector-java-5.1.44.jar"/> <!-- 一个数据库一个context --> <context id="infoGuardian"> <!-- 注释 --> <commentGenerator> <property name="suppressAllComments" value="true"/><!-- 是否取消注释 --> <property name="suppressDate" value="true"/> <!-- 是否生成注释代时间戳 --> </commentGenerator> <!-- jdbc连接 --> <jdbcConnection driverClass="${jdbc.driver}" connectionURL="${jdbc.url}" userId="${jdbc.username}" password="${jdbc.password}"/> <!-- 类型转换 --> <javaTypeResolver> <!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) --> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- 01 指定javaBean生成的位置 --> <!-- targetPackage:指定生成的model生成所在的包名 --> <!-- targetProject:指定在该项目下所在的路径 --> <javaModelGenerator targetPackage="com.CloudJun.model" targetProject="src/main/java"> <!-- 是否允许子包,即targetPackage.schemaName.tableName --> <property name="enableSubPackages" value="false"/> <!-- 是否对model添加构造函数 --> <property name="constructorBased" value="true"/> <!-- 是否针对string类型的字段在set的时候进行trim调用 --> <property name="trimStrings" value="false"/> <!-- 建立的Model对象是否 不可改变 即生成的Model对象不会有 setter方法,只有构造方法 --> <property name="immutable" value="false"/> </javaModelGenerator> <!-- 02 指定sql映射文件生成的位置 --> <sqlMapGenerator targetPackage="com.CloudJun.mapper" targetProject="src/main/java"> <!-- 是否允许子包,即targetPackage.schemaName.tableName --> <property name="enableSubPackages" value="false"/> </sqlMapGenerator> <!-- 03 生成XxxMapper接口 --> <!-- type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象 --> <!-- type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象 --> <!-- type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口 --> <javaClientGenerator targetPackage="com.CloudJun.mapper" targetProject="src/main/java" type="XMLMAPPER"> <!-- 是否在当前路径下新加一层schema,false路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] --> <property name="enableSubPackages" value="false"/> </javaClientGenerator> <!-- 配置表信息 --> <!-- schema即为数据库名 --> <!-- tableName为对应的数据库表 --> <!-- domainObjectName是要生成的实体类 --> <!-- enable*ByExample是否生成 example类 --> <!--<table schema="" tableName="t_book" domainObjectName="Book"--> <!--enableCountByExample="false" enableDeleteByExample="false"--> <!--enableSelectByExample="false" enableUpdateByExample="false">--> <!--<!– 忽略列,不生成bean 字段 –>--> <!--<!– <ignoreColumn column="FRED" /> –>--> <!--<!– 指定列的java数据类型 –>--> <!--<!– <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" /> –>--> <!--</table>--> <table schema="" tableName="t_hibernate_book" domainObjectName="HBook" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="false" enableUpdateByExample="false"> </table> <table schema="" tableName="t_hibernate_category" domainObjectName="Category" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="false" enableUpdateByExample="false"> </table> <table schema="" tableName="t_hibernate_book_category" domainObjectName="HBookCategory" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="false" enableUpdateByExample="false"> </table> <table schema="" tableName="t_hibernate_order" domainObjectName="Order" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="false" enableUpdateByExample="false"> </table> <table schema="" tableName="t_hibernate_order_item" domainObjectName="OrderItem" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="false" enableUpdateByExample="false"> </table> </context> </generatorConfiguration>
自动生成实体
创建一个 名为 OrderItemVo 的类,继承OrderItem类,及属性有Order对象
<!-- resultMap的映射--> <resultMap id="OrderVoMap" type="com.lya.vo.OrderVo" > <result column="order_id" property="orderId"></result> <result column="order_no" property="orderNo"></result> <!-- 一个对应多个--> <collection property="orderItems" ofType="com.lya.model.OrderItem"> <result column="order_id" property="orderId"></result> <result column="order_no" property="orderNo"></result> <result column="order_id" property="orderId"></result> <result column="order_no" property="orderNo"></result> </collection> </resultMap> <select id="byoid" resultMap=" " parameterType="java.lang.Integer" > select * from t_hibernate_order o , t_hibernate_order_item ot where o.order_id = ot.oid and o.order_id = #{oid} </select>
在自动生成的 OrderItemMapper 接口中进行增加以下代码
OrderItemVo selectByBiid(@Param("oiid") Integer oiid);
创建一个接口名为 : OrderItemBiz 接口
package com.lya.biz; import com.lya.vo.OrderItemVo; /** * @author 程序猿-小李哥 * @site www.xiaolige.com * @company 猪八戒有限集团 * @create 2023-09-04-9:38 */ public interface OrderItemBiz { OrderItemVo selectByBiid(Integer oiid); }
创建一个实现了名为 OrderItemBizImpl 类
package com.lya.biz.impl; import com.lya.biz.OrderItemBiz; import com.lya.mapper.OrderItemMapper; import com.lya.model.OrderItem; import com.lya.vo.OrderItemVo; import org.springframework.beans.factory.annotation.Autowired; /** * @author 程序猿-小李哥 * @site www.xiaolige.com * @company 猪八戒有限集团 * @create 2023-09-04-9:40 */ public class OrderItemBizImpl implements OrderItemBiz { @Autowired private OrderItemMapper orderItemMapper; @Override public OrderItemVo selectByBiid(Integer oiid) { return orderItemMapper.selectByBiid(oiid); } }
测试:
二,一对多
创建一个 名为 OrdeVo 的类,继承Order
package com.lya.vo; import com.lya.model.Order; import com.lya.model.OrderItem; import java.util.ArrayList; import java.util.List; /** * @author 程序猿-小李哥 * @site www.xiaolige.com * @company 猪八戒有限集团 * @create 2023-08-26-16:57 */ 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; } }
在自动生成的 OrderMapper.xml 配置文件中增加以下配置
<resultMap id="OrderVoMap" type="com.lya.vo.OrderVo"> <result column="order_id" property="orderId" ></result> <result column="order_no" property="orderNo" ></result> <collection property="orderItems" ofType="com.lya.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="selectByOid" resultMap="OrderVoMap" 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>
在自动生成的 OrderMapper接口中进行增加以下代码
OrderVo selectByOid(@Param("oid") Integer oid);
创建一个接口名为 : OrderBiz 接口
package com.lya.biz; import com.lya.vo.OrderVo; /** * @author 程序猿-小李哥 * @site www.xiaolige.com * @company 猪八戒有限集团 * @create 2023-09-04-10:04 */ public interface OrderBiz { OrderVo selectByOid(Integer oid); }
创建一个实现类,名为 OrderBizImpl
package com.lya.biz.impl; import com.lya.biz.OrderBiz; import com.lya.mapper.OrderMapper; import com.lya.vo.OrderVo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author 程序猿-小李哥 * @site www.xiaolige.com * @company 猪八戒有限集团 * @create 2023-09-04-10:05 */ @Service public class OrderBizImpl implements OrderBiz { @Autowired private OrderMapper orderMapper; @Override public OrderVo selectByOid(Integer oid) { return orderMapper.selectByOid(oid); } }
测试:
@Autowired private OrderBiz orderBiz; @Test public void selectByOid() { OrderVo orderVo = orderBiz.selectByOid(7); System.out.println(orderVo); orderVo.getOrderItems().forEach(System.out::println); }
三,多对多
在自动生成的 HBookMapper.xml 配置文件中增加以下配置
<resultMap id="HBookVoMap" type="com.lya.vo.HBookVo" > <result column="book_id" property="bookId"></result> <result column="book_name" property="bookName"></result> <result column="price" property="price"></result> <collection property="categories" ofType="com.lya.model.Category"> <result column="category_id" property="categoryId"></result> <result column="category_name" property="categoryName"></result> </collection> </resultMap> <select id="selectByBookId" resultMap="HBookVoMap" 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>
在自动生成的 HBookMapper 接口 中增加以下方法
HBookVo selectByBookId(@Param("bid") Integer bid);
创建一个接口名为 HBookBiz
package com.lya.biz; import com.lya.vo.HBookVo; import org.apache.ibatis.annotations.Param; /** * @author 程序猿-小李哥 * @site www.xiaolige.com * @company 猪八戒有限集团 * @create 2023-09-04-10:13 */ public interface HBookBiz { HBookVo selectByBookId(@Param("bid") Integer bid); }
创建一个实现类,名为 HBookBizImpl
package com.lya.biz.impl; import com.lya.biz.HBookBiz; import com.lya.mapper.HBookMapper; import com.lya.vo.HBookVo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author 程序猿-小李哥 * @site www.xiaolige.com * @company 猪八戒有限集团 * @create 2023-09-04-10:13 */ @Service public class HBookBizImpl implements HBookBiz { @Autowired private HBookMapper hBookMapper; @Override public HBookVo selectByBookId(Integer bid) { return hBookMapper.selectByBookId(bid); } }
测试
@Autowired private HBookBiz hbookBiz; @Test public void selectByBookId() { HBookVo hBookVo = hbookBiz.selectByBookId(8); System.out.println(hBookVo); hBookVo.getCategories().forEach(System.out::println); }
总结
学习Mybatis的关联关系映射可以带来以下收获和认识:
1. 数据库关系的抽象:学习MyBatis的关联关系映射可以有助于我们理解数据库中表与表之间的关系,如一对一和一对多关系。这可以提升我们对数据模型的理解和设计能力。
2. 对象关系映射(ORM)的学习:MyBatis采用了ORM的思想,通过映射配置将数据库表与Java对象进行关联。学习MyBatis的关联关系映射可以帮助我们掌握ORM的基本原理和实践技巧。
3. 数据库操作的灵活性:MyBatis的关联关系映射使得数据库操作更加灵活,能够方便地进行多表查询或关联查询。这有助于我们优化数据库访问性能,并提供更好的数据查询和操作能力。
4. 代码重用和维护性:通过MyBatis的关联关系映射,我们可以将一对一或一对多关系的查询逻辑封装成可复用的SQL语句或映射文件片段,提高代码的重用性和可维护性。
5. 高效的数据库访问:MyBatis的关联关系映射能够有效地利用数据库的连接和查询优化,减少不必要的数据库访问,提高数据库操作的效率。
这些收获和认识将帮助我们更好地应对实际项目中的数据库操作需求,并提升我们作为Java程序员的能力和竞争力。