不是原创,整理尚硅谷的内容得到的
六、自定义映射ResultMap
①处理字段和属性名不一致的情况
处理字段名和属性名不一致的方式一:为表中字段增加别名:
select emp_id empId,emp_name empName,age,gender from t_emp where emp_id=#{empId}
注意,表中没有empId和empName两个字段,MyBatis是根据查询结果的字段名为属性名赋值,这边字段名和属性名不一致,肯定是对应不上的。
方式二:设置一个全局配置
在全局配置中设置标签:
<setting name="mapUnderscoreToCamelCase" value="true"/>
这个标签必须要求符合MySQL和java命名规范才可以继续,Mybatis中的核心配置文件中设置一个全局配置,自动将下划线转化为驼峰
方式三:使用resultMap进行操作
<resultMap id="EmpAndDept" type="Emp"> <id column="emp_id" property="empId"></id> <result column="emp_name" property="empName"></result> <result column="age" property="age"></result> <result column="gender" property="gender"></result> </resultMap>
最上面id表示这个标签的唯一标识(这个id要和sql语句进行关联),type表示要处理的实体类
result处理普通字段和实体类对应关系
id用于处理主键
②处理多对一的映射关系(主要有三种方式):
方式一:多表联查,也就是用级联的方式,这时也是设置一个ResultMap就可以了,具体看下面这段代码:
<resultMap id="EmpAndDept" type="Emp"> <id column="emp_id" property="empId"></id> <result column="emp_name" property="empName"></result> <result column="age" property="age"></result> <result column="gender" property="gender"></result> <result column="dept_id" property="dept.deptId"></result> <result column="dept_name" property="dept.deptName"></result> </resultMap>
<select id="getEmpAndDeptByEmpIdOne" resultMap="EmpAndDept"> select t_emp.*,t_dept.* from t_emp left join t_dept on t_emp.dept_id = t_dept.dept_id where t_emp.emp_id=#{empId} </select>
现在要通过员工id获取员工部门id和员工的全部信息,这时典型的多对一(多个员工对应一个部门),那么要在员工信息里面多一个属性(这个属性就是部门),这个时候MyBatis进行查询的时候,对于查询的结果dept_id和dept_name,由于我们在员工类中没有这两个属性,因此没有办法进行赋值,于是要用resultMap进行对应。
方式二:使用association处理映射关系
<resultMap id="empAndDeptResultMap" type="Emp"> <id column="emp_id" property="empId"></id> <result column="emp_name" property="empName"></result> <result column="age" property="age"></result> <result column="gender" property="gender"></result> <association property="dept" javaType="Dept"> <id column="dept_id" property="deptId"></id> <id column="dept_name" property="deptName"></id> </association> </resultMap>
标签property是用来表示要处理的属性,而javaType是设置要处理的属性的类型,这里本该写全类名,但是由于我在核心配置文件中为类型起了别名,所以可以这样写。
方式三:分布查询,写成两个sql语句
查询一:
<resultMap id="empAndDeptByStepResultResultMap" type="Emp"> <id column="emp_id" property="empId"></id> <result column="emp_name" property="empName"></result> <result column="age" property="age"></result> <result column="gender" property="gender"></result> <association property="dept" fetchType="lazy" select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo" column="dept_id"> </association> </resultMap> <select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultResultMap"> select *from t_emp where emp_id=#{empId} </select>
查询二:
<select id="getEmpAndDeptByStepTwo" resultType="Dept"> select *from t_dept where dept_id=#{deptId} </select>
说白了就是查两次,第一次查询部门id,第二次用查到的部门id去查询部门的信息;
这时association标签中字段有下面的含义:
Properties表示设置需要处理映射关系的属性的属性名
select表示我要跳转到哪个sql语句,注意这边(namespace+sql的id构成sql的唯一标识,也就是Mapper接口的抽象方法的全类名)
column表示将sql查询结果的某个字段作为分步查询的条件
这种方法单独有优势:
可以实现懒加载,也就是如果我单独只要获取员工姓名,那么也就不需要进行加载dept的信息了,此时只需要(核心)配置下面两个标签就可以了,也可以通过上面所描述的fetchType="lazy"标签来进行处理。
<!--延迟加载全局开关--> <setting name="lazyLoadingEnabled" value="true"/> <!-- aggressiveLazyLoading 当开启时,任何sql查询的加载会导致所有属性的加载 --> <setting name="aggressiveLazyLoading" value="false"/>
③处理一对多的映射关系
下面要查询一个部门里面的所有员工信息,那么要为部门类添加一个list这个属性,为这个属性加上泛型:员工。这时候只有两种处理方式:多步查询和collection。
方式一:使用Collection进行处理
<resultMap id="DeptAndEmpResultMap" type="Dept"> <id column="dept_id" property="deptId"></id> <result column="dept_name" property="deptName"></result> <collection property="emps" ofType="Emp"> <id column="emp_id" property="empId"></id> <result column="emp_name" property="empName"></result> <result column="age" property="age"></result> <result column="gender" property="gender"></result> </collection> </resultMap>
<!-- 要处理的是Dept,因为Dept中有一个属性找不到映射关系,这边是处理映射关系的,所以Type是dept-->
ofType用于处理表与集合的映射关系,下面就和Collection是一样的了。
方式二:使用多步查询
先查询部门id,再根据部门id查询员工信息
两个接口分别如下:
Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId); List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") Integer deptId);
对应的映射文件如下
resultMap id="DeptAndEmpByStepOne" type="Dept"> <id column="dept_id" property="deptId"></id> <result column="dept_name" property="deptName"></result> <collection property="emps" select="com.atguigu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo" column="dept_id"> <!--以dept_id为条件,我们是先查询部门的dept_id再根据部门的dept_id查询我要的emp的信息--> </collection> </resultMap> <select id="getDeptAndEmpByStepOne" resultMap="DeptAndEmpByStepOne"> select*from t_dept where dept_id=#{deptId} </select>
<!-- List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") Integer deptId);--> <select id="getDeptAndEmpByStepTwo" resultType="Emp"> select *from t_emp where dept_id=#{deptId} </select>
这个没有什么创新,和前面也大同小异
七、动态sql
动态sql就是几个标签
标签一:if标签
if标签:通过if判断标签中的内容是否有效,即标签中的内容是否会拼接到SQL中
比方说,服务器获取到信息后,如果得到的是空表示初始状态,如果获取的是空字符串表示客户没有填写信息,那么通过if标签可以判断是不是要将获取的信息拼接到sql语句当中,比如说:
<!-- List<Emp> getEmpByCondition(Emp emp);根据条件查询员工信息--> <select id="getEmpByConditionOne" resultType="Emp"> select * from t_emp where <if test="empName!=null and empName != ''"> 语句emp_name = #{empName} </if> <if test="age!=null and age !=''"> <!-- 目标是为了拼接到我的Emp对象当中--> and age=#{age} </if> <if test="gender!=null and gender !=''"> <!-- 目标是为了拼接到我的Emp对象当中--> and gender=#{gender} </if> </select>
表示如果字符串不是空对象或者不为空,那么才进行对sql的拼接,值得注意的是这边要手动添加and这一信息。
问题一:如果第一个emp_name是空,那么sql语句就变为
select * from t_emp where and 。。。。这显然有问题;
问题二:如果全是空那么,sql语句select * from t_emp where也有问题
这时可以添加1=1,然后if第一个标签中添加and即可,即:
<!-- List<Emp> getEmpByCondition(Emp emp);根据条件查询员工信息--> <select id="getEmpByConditionOne" resultType="Emp"> select * from t_emp where 1=1 <if test="empName!=null and empName != ''"> and emp_name = #{empName} </if> <if test="age!=null and age !=''"> <!-- 目标是为了拼接到我的Emp对象当中--> and age=#{age} </if> <if test="gender!=null and gender !=''"> <!-- 目标是为了拼接到我的Emp对象当中--> and gender=#{gender} </if> </select>
标签二:where标签,where标签有三个功能
作用一:自动生成where关键字
作用二:自动将多余的前面的and去掉,内容后多余的and没有办法去掉
作用三:where标签中没有任何一个标签成立,where中没有任何功能
可以发现,运用where标签也可以解决上面的问题。
<select id="getEmpByConditionTwo" resultType="Emp"> select *from t_emp <where> <if test="empName!=null and empName != ''"> emp_name = #{empName} </if> <if test="age!=null and age !=''"> <!-- 目标是为了拼接到我的Emp对象当中--> and age=#{age} </if> <if test="gender!=null and gender !=''"> <!-- 目标是为了拼接到我的Emp对象当中--> and gender=#{gender} </if> </where> </select>
标签三:trim标签
prefix与suffix:在标签前面后者后面添加指定内容 prefixOverWrides和suffixOverrides:在标签中内容前面或者后面去掉指定内容
比方说(这个代码表示前面接上where后面去掉and然后进行操作):
<select id="getEmpByCondition" resultType="Emp"> select* from t_emp <trim prefix="where" suffixOverrides="and"> <if test="empName!=null and empName != ''"> emp_name = #{empName} and </if> <if test="age!=null and age !=''"> <!-- 目标是为了拼接到我的Emp对象当中--> age=#{age} and </if> <if test="gender!=null and gender !=''"> <!-- 目标是为了拼接到我的Emp对象当中--> gender=#{gender} </if> </trim> </select>
标签四:choose...when...otherwise(if...else if...else)进行处理操作,
其实也就是switch。。。case结构
<!-- List<Emp>getEmpByChoose(Emp emp);--> <select id="getEmpByChoose" resultType="Emp"> select *from t_emp <where> <choose> <when test="empName!=null and empName != ''"> emp_name = #{empName} </when> <when test="age!=null and age !=''"> age=#{age} </when> <when test="gender!=null and gender !=''"> gender=#{gender} </when> </choose> </where> </select>
标签四:forEach标签
Collection:设置要循环的数组或者集合 item:用一个数组表示数组或集合中的每一个数据 separator:用于设置每一次循环数据的分隔符 open:循环的所有内容,以什么开始 close:循环的所有内容,以什么结束
如下面所示:
<!-- void insertMoreEmp(@params(list)List<Emp> emps);--> <insert id="insertMoreEmp"> insert into t_emp values <!-- item 表示数组或者集合中的元素数据--> <foreach collection="list" item="emp" separator=","> (null,#{emp.empName},#{emp.age},#{emp.gender},null) </foreach> </insert> <!-- void deleteMoreEmp(@Param("empIds") Integer[] empIds);--> <delete id="deleteMoreEmp"> delete from t_emp where emp_id in <!-- open和close用来设置左括号和右括号以什么开始--> <foreach collection="empIds" item="empId" separator="," open="(" close=")"> #{empId} </foreach> </delete>
标签五:sql标签
所谓sql标签就是可以记录一段公共sql片段,在使用的地方通过include标签进行引入
比如说,如下所示:
<sql id="empColumns"> emp_id,emp_name,age,gender,dept_id </sql>
<include></include>标签,在需要引用的地方,进行引用
<select id="getEmpByCondition" resultType="Emp"> select <include refid="empColumns"></include> from t_emp <trim prefix="where" suffixOverrides="and"> <if test="empName!=null and empName != ''"> emp_name = #{empName} and </if> <if test="age!=null and age !=''"> <!-- 目标是为了拼接到我的Emp对象当中--> age=#{age} and </if> <if test="gender!=null and gender !=''"> <!-- 目标是为了拼接到我的Emp对象当中--> gender=#{gender} </if> </trim> </select>