赞
踩
上一篇文章中荔枝梳理了有关MyBatis的相关环境配置和核心配置文件及其模板的设置和生成,而在这篇文章中荔枝会着重梳理MyBatis多种查询情况、特殊SQL执行以及两表联查时映射关系的处理。希望对需要的小伙伴有帮助~~~
2.2.3 association分步查询解决多对一映射问题
在MyBatis中,对于数据库的查询来说,如果查询出来的数据只有一条,可以通过实体类对象或者集合(list、map)来接收,如果查询的数据有多条,则一定不能通过实体类来接收,否则会抛出异常TooManyResultException。
实体类对象:
User getUserById(@Param("id") Integer id);
list集合:
List<User> getAllUser(@Param("id") Integer id);
map集合
Map<String,Object> getUserByIdToMap(@Param("id") Integer id);
list集合:
List<User> getAllUser(@Param("id") Integer id);
map集合:
List<Map<String,Object>> getAllUserToMap(@Param("id") Integer id);
或者借助@MapKey注解
- @MapKey("id") //把查询到的数据的某一个字段作为key,查询到的所有数据作为值value
- Map<String,Object> getAllUserToMap2(@Param("id") Integer id);
在MyBatis中,大多数的查询都可以使用#{}的格式来获取参数,但是有一些特殊SQL的执行则不能直接采用#{}的格式。
采用${}格式
- <mapper namespace="com.crj.mapper.SQLMapper">
- <!-- List<User> getUserByLike(@Param("username") String username);-->
- <select id="getUserByLike" resultType="User">
- select * from t_user where username like '%${username}%'
- </select>
- </mapper>
采用concat拼接并采用#{}
- <mapper namespace="com.crj.mapper.SQLMapper">
- <!-- List<User> getUserByLike(@Param("username") String username);-->
- <select id="getUserByLike" resultType="User">
- select * from t_user where username like concat('%',#{username},'%')
- </select>
- </mapper>
采用" "拼接SQL
- <mapper namespace="com.crj.mapper.SQLMapper">
- <!-- List<User> getUserByLike(@Param("username") String username);-->
- <select id="getUserByLike" resultType="User">
- select * from t_user where username like "%"#{username}"%"
- </select>
- </mapper>
在执行批量删除的时候为什么不能使用#{}?这是因为#{}会自动加上单引号从而导致SQL异常无法实现批量删除的功能。
- <!-- int deleteMore(@Param("ids") String ids);-->
- <delete id="deleteMore">
- delete from t_user where id in (${ids})
- </delete>
在数据库执行完水平分表之后,MyBatis在执行数据操作的时候就需要动态设置表名从而实现分表查询。这里因为表名是不能加单引号的,所以这里还是采用${}的形式来实现动态分表查询。
- <!-- List<User> getUserByTableName(@Param("tableName") String tableName);-->
- <select id="getUserByTableName" resultType="User">
- select * from ${tableName} where id=1
- </select>
插入数据时使用自增主键需要设置insert标签的两个属性:
- <!-- void insertUser(User user);-->
- <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
- insert into t_user values (null,#{username},#{password})
- </insert>
在之前我们使用resultType要求字段名和属性名一致,使用的是一种默认的自动创建的映射关系。但是当字段名和属性名不一致的时候或者处理一对多和多对一的映射关系的时候,我们需要自定义映射关系resultMap。
- <select id="getAllEmp" resultType="Emp">
- select eid,emp_name empName from t_emp
- </select>
- <!--设置mybatis的全局设置-->
- <settings>
- <!-- mapUnderscoreToCameCase:将下划线映射到驼峰命名,默认是false不支持-->
- <setting name="mapUnderscoreToCameCase" value="true"/>
- </settings>
通过将mapUnderscoreToCameCase属性值设置为true,开启mybatis将下划线映射为驼峰命名的功能
- <?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="com.crj.mybatis.mapper.EmpMapper">
- <!-- List<Emp> getAllEmp();-->
- <resultMap id="empResultMap" type="Emp">
- <!--使用resultMap后建议要把所有字段名和属性之间的关系都声明出来-->
- <id property="eid" column="eid"/>
- <result column="emp_name" property="empName"/> <!--注意这里的映射关系-->
- <result column="age" property="age"/>
- <result column="sex" property="sex"/>
- </resultMap>
- <select id="getAllEmp" resultMap="empResultMap">
- select * from t_emp
- </select>
- </mapper>
id:唯一标识,不能重复
type:设置映射关系中的实体类类型
这里有两个子标签:id和result。
id:设置主键的映射关系
result:设置普通字段的映射关系
属性 :
property:设置映射关系中的属性名,必须是type属性所设置的实体类类型的属性名
column:设置映射关系中的字段名,是SQL语句查询出的字段名
这里有员工和部门两张表,分别为二者创建实现类Emp和Dept。在多对一的映射关系中,我们考虑的是多个员工同属于一个部门。
- package com.crj.mybatis.pojo;
-
- public class Emp {
- private Integer eid;
- private String empName;
- private Integer age;
- private String sex;
- private String email;
- private Dept dept;
-
- @Override
- public String toString() {
- return "Emp{" +
- "eid=" + eid +
- ", empName='" + empName + '\'' +
- ", age=" + age +
- ", sex='" + sex + '\'' +
- ", email='" + email + '\'' +
- ", dept=" + dept +
- '}';
- }
-
- public Dept getDept() {
- return dept;
- }
-
- public void setDept(Dept dept) {
- this.dept = dept;
- }
-
- public Emp(Integer eid, String empName, Integer age, String sex, String email) {
- this.eid = eid;
- this.empName = empName;
- this.age = age;
- this.sex = sex;
- this.email = email;
- }
- public Emp(){}
-
- public Integer getEid() {
- return eid;
- }
-
- public void setEid(Integer eid) {
- this.eid = eid;
- }
-
- public String getEmpName() {
- return empName;
- }
-
- public void setEmpName(String empName) {
- this.empName = empName;
- }
-
- public Integer getAge() {
- return age;
- }
-
- public void setAge(Integer age) {
- this.age = age;
- }
-
- public String getSex() {
- return sex;
- }
-
- public void setSex(String sex) {
- this.sex = sex;
- }
-
- public String getEmail() {
- return email;
- }
-
- public void setEmail(String email) {
- this.email = email;
- }
- }
- <resultMap id="getEmpAndDept" type="Emp">
- <id property="eid" column="eid"/>
- <result column="emp_name" property="empName"/>
- <result column="age" property="age"/>
- <result column="sex" property="sex"/>
-
- <result column="did" property="dept.did"/>
- <result column="dept_name" property="dept.deptName"/>
-
- </resultMap>
- <!-- Emp getEmpAndDept(@Param("eid") Integer eid);-->
- <select id="getEmpAndDept" resultMap="getEmpAndDept">
- select * from t_emp left join t_dept on t_emp.did=t_dept.did where t_emp.eid = #{eid}
- </select>
其中,对于association中的属性我们需要了解:
- <resultMap id="getEmpAndDept" type="Emp">
- <id property="eid" column="eid"/>
- <result column="emp_name" property="empName"/>
- <result column="age" property="age"/>
- <result column="sex" property="sex"/>
-
- <association property="dept" javaType="Dpet">
- <id property="did" column="did"></id>
- <result property="deptName" column="dept_name"></result>
- </association>
-
- </resultMap>
此时association中的property属性的含义不变,但还有两个比较重要的属性需要设置相应的属性值
分步查询的第一步:查询员工信息
EmpMapper.java
- package com.crj.mybatis.mapper;
-
- import com.crj.mybatis.pojo.Emp;
- import org.apache.ibatis.annotations.Param;
-
- import java.util.List;
-
- public interface EmpMapper {
-
- /**
- * 通过分布查询员工以及员工所对应的部门信息
- * 分布查询第一步:查询员工信息
- */
- Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);
- }
EmpMapper.xml
- <?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="com.crj.mybatis.mapper.EmpMapper">
- <!-- 分步查询,两表联查-->
- <resultMap id="empAndDeptByStepResultMap" type="Emp">
- <id property="eid" column="eid"/>
- <result column="emp_name" property="empName"/>
- <result column="age" property="age"/>
- <result column="sex" property="sex"/>
-
- <association property="dept"
- select="com.crj.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
- column="did"></association>
- </resultMap>
- <!-- Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);-->
- <select id="getEmpAndDeptByStepOne" resultMap="empAndDeptResultMapTwo">
- select * from t_emp where eid = #{eid}
- </select>
-
- </mapper>
分步查询第二步:根据查询到的员工信息中的did来查询相应的部门信息
DpetMapper.java
- package com.crj.mybatis.mapper;
-
- import com.crj.mybatis.pojo.Dept;
- import org.apache.ibatis.annotations.Param;
-
- public interface DeptMapper {
- /**
- * 通过分布查询员工以及员工所对应的部门信息
- * 分布查询第二步:通过did查询员工所对应的部门
- */
- Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);
-
- }
DeptMapper.xml
- <?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="com.crj.mybatis.mapper.DeptMapper">
- <!-- Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);-->
- <select id="getEmpAndDeptByStepTwo" resultType="Dept">
- select * from t_dept where did = #{did}
- </select>
- </mapper>
需要注意的是,分步查询在实际的应用场景中使用的会比较多。
注意:为什么更推荐使用分步查询呢?
这是因为通过分步查询我们可以实现MyBatis的延迟加载(懒加载 )功能,通过分步查询我们可以做到需要查询什么信息就执行什么SQL语句,比如我们仅需要查询员工信息而不需要部门的内容时,通过延迟加载我们只会执行EmpMapper中的SQL语句,同时分步查询也实现了两种不同的查询功能的隔离。MyBatis中默认是不会开启延迟加载的功能滴,
要想实现延迟加载的功能,就必须在全局配置文件中开启相应的延迟加载的开关:
开启延迟加载时针对于当前的所有的分步查询,如果哪一步不需要延迟加载可通过association和collection中的fetchType属性设置当前的分步查间是否使用延迟加载,fetchType="lazy(延迟加载) l eager(立即加载)'
- <settings>
- <!-- 开启延迟加载-->
- <setting name="lazyLoadingEnabled" value="true"/>
- </settings>
Dpet.java
- //一对多的映射关系
- private List<Emp> emps;
DeptMapper.java
- /**
- * 以部门为主表来获取部门中所有的员工信息
- */
- Dept getDeptAndEmp(@Param("did") Integer did);
DeptMapper.xml
- <resultMap id="deptAndEmpResultMap" type="Dept">
- <id property="did" column="did"></id>
- <result property="deptName" column="dept_name"></result>
-
- <!--注意区分ofType和association中属性javaType的区别-->
- <collection property="emps" ofType="Emp">
- <id property="did" column="did"></id>
- <result property="empName" column="emp_name"></result>
- <result property="age" column="age"></result>
- <result property="sex" column="sex"></result>
- <result property="email" column="email"></result>
- </collection>
-
- </resultMap>
- <!-- Dept getDeptAndEmp(@Param("did") Integer did);-->
- <select id="getDeptAndEmp" resultMap="deptAndEmpResultMap">
- select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
- </select>
分步查询的第一步:查询部门信息
DeptMapper.java
- package com.crj.mybatis.mapper;
-
- import com.crj.mybatis.pojo.Dept;
- import org.apache.ibatis.annotations.Param;
-
- public interface DeptMapper {
-
- /**
- * 分步查询处理一对多的关系
- * 第一步:查询部门信息
- */
- Dept getDeptAndEmpByStepOne(@Param("did") Integer did);
-
- }
DeptMapper.xml
- <?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="com.crj.mybatis.mapper.DeptMapper">
-
- <resultMap id="deptAndEmpByStepResultMap" type="Dept">
- <id property="did" column="did"></id>
- <result property="deptName" column="dept_name"></result>
- <collection property="emps" select="com.crj.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo" column="did"></collection>
- </resultMap>
- <!-- Dept getDeptAndEmpByStepOne(@Param("did") Integer did);-->
- <select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpByStepResultMap">
- select * from t_dept where did = #{did}
- </select>
- </mapper>
分步查询第二步:根据查询到的员工信息中的did来查询相应的部门信息
EmpMapper.java
- package com.crj.mybatis.mapper;
-
- import com.crj.mybatis.pojo.Emp;
- import org.apache.ibatis.annotations.Param;
-
- import java.util.List;
-
- public interface EmpMapper {
-
- /**
- * 分步查询处理一对多的关系
- * 第二步:根据did查询员工信息
- */
- List<Emp> getDeptAndEmpByStepTwo();
- }
EmpMapper.xml
- <?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="com.crj.mybatis.mapper.EmpMapper">
-
- <!-- List<Emp> getDeptAndEmpByStepTwo();-->
- <select id="getDeptAndEmpByStepTwo" resultType="Emp">
- select * from t_emp where did = #{did}
- </select>
-
- </mapper>
弄清楚两种映射关系以及相应的文件依赖关系和处理无疑时学习的重点,荔枝学习的时候也是感觉好像懂了,但复盘的时候还是有很多概念明显没有弄清楚。最近荔枝的学习状态有点波动,可能是摆烂了两周的缘故。。。接下来荔枝也会调整状态滴,继续学习Java后端技术栈并作出相应的Blog输出。最近看了丙哥的文章,喜欢一句话分享给大家:你知道的越多,你不知道的越多。共勉共勉哈哈哈哈~~~
今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。