文章目录
前言
如果从数据库查询出来的数据无法直接映射会实体类对象,那么就可以通过自定义映射来解决这个问题
一、自定义映射是什么?
resultMap 是自定义的映射关系,可实现高级结果集映射。
注意:resultMap 不能与 resultType 同时使用。
二、使用场景
场景一:字段名和属性名不一致
若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性
名符合Java的规则(使用驼峰)如字段名user_name,属性名userName
可通过以下两种方式处理字段名和实体类中的属性的映射关系:
1.为字段起别名的方式,保证和实体类中的属性名保持一致
即查询语句中设置:select userName,password,age,sex from table
而不使用select * from table
2.在MyBatis的核心配置文件中设置一个全局配置信息mapUnderscoreToCamelCase
可以在查询表中数据时,自动将_类型的字段名转换为驼峰
设置全局配置之后只需要常规使用select * from table
返回的数据字段名虽然还是user_name,当时mybatis框架会自动将此类型的字段名转化为userName(即驼峰命名)
3.通过自定义映射一一指定每一个字段所要映射的属性
场景二:单表查询返回的字段和成员属性不匹配(即多对一,一对多映射)
-
什么是多对一关系:多对一关系就是表A中多条数据对应表B中的一条数据,例如,员工和部门之间的关系,多名员工可以属于同一部门
多对一映射:
若需要查询员工以及所对应的部门信息时,此时查询模型为多对一映射
由于员工对象属性中存在类属性即dept类属性,因此通过两表联查返回来的数据并没有办法直接进行赋值给员工对象属性,此时有三种方法来解决这个问题:
-
使用级联的方式处理映射关系
-
使用association处理映射关系
-
分步查询
级联:
<resultMap id="empDeptMap" type="Emp">
<id column="eid" property="eid"></id>
<result column="ename" property="ename"></result>
<result column="age" property="age"></result>
<result column="sex" property="sex"></result>
<result column="did" property="dept.did"></result>
<result column="dname" property="dept.dname"></result>
</resultMap>
<!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
<select id="getEmpAndDeptByEid" resultMap="empDeptMap">
select emp.*,dept.* from t_emp emp left join t_dept dept on emp.did =
dept.did where emp.eid = #{eid}
</select>
两表联查之后直接将did,dname部门属性赋值给员工对象中的成员变量dept,通过dept.did,dept.dname这种方式就可以指定要为成员变量的哪一个属性来进行赋值
association方式:
<resultMap id="empDeptMap" type="Emp">
<id column="eid" property="eid"></id>
<result column="ename" property="ename"></result>
<result column="age" property="age"></result>
<result column="sex" property="sex"></result>
<association property="dept" javaType="Dept">
<id column="did" property="did"></id>
<result column="dname" property="dname"></result>
</association>
</resultMap>
<!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
<select id="getEmpAndDeptByEid" resultMap="empDeptMap">
select emp.*,dept.* from t_emp emp left join t_dept dept on emp.did =
dept.did where emp.eid = #{eid}
</select>
员工表和部门表两表联查之后,通过association标签就不需要在指定成员变量属性所对应的类名了,即property=did这样写既可以进行赋值,不需要指定该属性所对应的类名dept,相较于上一个级联的方式较于简便,尤其是当该成员变量中的属性比较多时效果尤为明显。
分步查询:
第一步:
<resultMap id="empDeptStepMap" type="Emp">
<id column="eid" property="eid"></id>
<result column="ename" property="ename"></result>
<result column="age" property="age"></result>
<result column="sex" property="sex"></result>
<!--
select:设置分步查询,查询某个属性的值的sql的标识(namespace.sqlId)
column:将sql以及查询结果中的某个字段设置为分步查询的条件
-->
<association property="dept"
select="com.example.MyBatis.mapper.DeptMapper.getEmpDeptByStep" column="did">
</association>
</resultMap>
<!--Emp getEmpByStep(@Param("eid") int eid);-->
<select id="getEmpByStep" resultMap="empDeptStepMap">
select * from t_emp where eid = #{eid}
</select>
要查询员工和部门的信息,也可以通过分布查询的方式来获取,第一步先查询员工信息,然后将员工信息中的部门ID(deptid)作为第二部查询的条件来获取部门数据,通过association标签中的select标签来指定第二步要执行的方法的位置,column为方法参数,返回的结果会直接赋值给property="dept"
第二步:
<!--Dept getEmpDeptByStep(@Param("did") int did);-->
<select id="getEmpDeptByStep" resultType="Dept">
select * from t_dept where did = #{did}
</select>
根据第一步查询的部门ID查询部门,并将结果返回对应属性
一对多映射:
-
什么是一对多关系:一对多关系就是表A中一条数据对应表B中的多条数据,例如,员工和部门之间的关系,一个部门可以有多个员工信息。
若要查询一个部门信息以及部门内所有的员工信息,此时的模型为一对多映射
即部门对象dept中有成员变量emps,该变量为list集合类型,里面包含所有属于该部门的员工的信息
处理一对多映射的方法有两种:
-
collection
-
分步查询
collection查询:
<resultMap id="deptEmpMap" type="Dept">
<id property="did" column="did"></id>
<result property="dname" column="dname"></result>
<!--
ofType:设置collection标签所处理的集合属性中存储数据的类型
-->
<collection property="emps" ofType="Emp">
<id property="eid" column="eid"></id>
<result property="ename" column="ename"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
</collection>
</resultMap>
<!--Dept getDeptEmpByDid(@Param("did") int did);-->
<select id="getDeptEmpByDid" resultMap="deptEmpMap">
select dept.*,emp.* from t_dept dept left join t_emp emp on dept.did =
emp.did where dept.did = #{did}
</select>
部门表左外连接员工表之后通过collection集合可以将查询出来的数据中关于员工信息的数据不断地循环赋值到emps员工集合之中
分布查询:
第一步:
<resultMap id="deptEmpStep" type="Dept">
<id property="did" column="did"></id>
<result property="dname" column="dname"></result>
<collection property="emps" fetchType="eager"
select="com.atguigu.MyBatis.mapper.EmpMapper.getEmpListByDid" column="did">
</collection>
</resultMap>
<!--Dept getDeptByStep(@Param("did") int did);-->
<select id="getDeptByStep" resultMap="deptEmpStep">
select * from t_dept where did = #{did}
</select>
先通过部门ID获取部门信息,然后通过第二步查询获取员工信息赋值给部门对象中的emps集合属性,其中collection标签用来指定需要映射回去的数据的类型并循环赋值,select标签用来指定第二步查询的方法位置,column指定查询的条件
第二步:
<!--List<Emp> getEmpListByDid(@Param("did") int did);-->
<select id="getEmpListByDid" resultType="Emp">
select * from t_emp where did = #{did}
</select>
通过部门ID查询员工信息并将返回的数据赋值给部门的emps员工集合属性
当然:分步查询有着良好的查询优势:即延迟加载和按需加载
例如当映射方法写的是分步查询,当我们只需要部门的名字deptName的时候,可以通过开启延迟加载来让第二部查询员工信息的方法不执行,这样就可以减少不必要的运算消耗,提高系统的流畅性能,那么怎么实现分步加载的功能:
首先需要在核心配置文件mybatis-config.xml中设置全局配置信息: lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象(即分步查询)都会延迟加载 aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属 性会按需加载 此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。当然也可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载, fetchType="lazy(延迟加 载)|eager(立即加载)"
总结
以上就是mybatis自定义映射的相关知识点啦,如果你觉得文章对你有帮助的话,可以分享给你的好友看哦,分享的知识让我们共同进步,一起见证对方的成长!!!