实体类例子

下面的代码例子都是用到这两个实体类

员工实体类

  1. public class Emp {
  2. private Integer eid;
  3. private String empName;//在数据库中叫emp_name
  4. private Integer age;
  5. private String sex;
  6. private String email;
  7. private Dept dept;//部门部门对象,多对一
  8. //...构造器、get、set方法等
  9. }

部门实体类

  1. public class Dept {
  2. private Integer did;
  3. private String deptName;//数据库中叫dep_name
  4. private List<Emp> emps;//员工集合,一对多
  5. //...构造器、get、set方法等
  6. }

resultMap处理字段和属性的映射关系

若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射,即使字段名和属性名一致的属性也要映射,也就是全部属性都要列出来。
写一个单独的resultMap标签

  • resultMap:设置自定义映射

    • id:表示自定义映射的唯一标识,不能重复
    • type:查询的数据要映射的实体类的类型
  • 子标签:

    • :设置主键的映射关系
    • :设置普通字段的映射关系
  • 子标签属性:

    • property:设置映射关系中实体类中的属性名
    • column:设置映射关系中表中的字段名
  1. <resultMap id="empResultMap" type="Emp">
  2. <id property="eid" column="eid"></id>
  3. <result property="empName" column="emp_name"></result>
  4. <result property="age" column="age"></result>
  5. <result property="sex" column="sex"></result>
  6. <result property="email" column="email"></result>
  7. </resultMap>
  8. <!--List<Emp> getAllEmp();-->
  9. <select id="getAllEmp" resultMap="empResultMap">
  10. select * from t_emp
  11. </select>

若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性名符合Java的规则(使用驼峰)。此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系 。

  1. 可以通过为字段起别名的方式,保证和实体类中的属性名保持一致

    1. <!--List<Emp> getAllEmp();-->
    2. <select id="getAllEmp" resultType="Emp">
    3. select eid,emp_name empName,age,sex,email from t_emp
    4. </select>
  2. 可以在MyBatis的核心配置文件中的setting标签中,设置一个全局配置信息mapUnderscoreToCamelCase,可以在查询表中数据时,自动将_类型的字段名转换为驼峰,例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为userName

    1. <settings>
    2. <setting name="mapUnderscoreToCamelCase" value="true"/>
    3. </settings>

    多对一映射处理

    比如员工和部门之间的关系,多个员工一个部门

级联方式处理映射关系

  1. <resultMap id="empAndDeptResultMapOne" type="Emp">
  2. <id property="eid" column="eid"></id>
  3. <result property="empName" column="emp_name"></result>
  4. <result property="age" column="age"></result>
  5. <result property="sex" column="sex"></result>
  6. <result property="email" column="email"></result>
  7. <result property="dept.did" column="did"></result>
  8. <result property="dept.deptName" column="dept_name"></result>
  9. </resultMap>
  10. <!--Emp getEmpAndDept(@Param("eid")Integer eid);-->
  11. <select id="getEmpAndDept" resultMap="empAndDeptResultMapOne">
  12. select * from t_emp left join t_dept on t_emp.eid = t_dept.did where t_emp.eid = #{eid}
  13. </select>

使用association处理映射关系

  • association:处理多对一的映射关系
  • property:需要处理多对一的映射关系的属性名
  • javaType:该属性的类型

    1. <resultMap id="empAndDeptResultMapTwo" type="Emp">
    2. <id property="eid" column="eid"></id>
    3. <result property="empName" column="emp_name"></result>
    4. <result property="age" column="age"></result>
    5. <result property="sex" column="sex"></result>
    6. <result property="email" column="email"></result>
    7. <association property="dept" javaType="Dept">
    8. <id property="did" column="did"></id>
    9. <result property="deptName" column="dept_name"></result>
    10. </association>
    11. </resultMap>
    12. <!--Emp getEmpAndDept(@Param("eid")Integer eid);-->
    13. <select id="getEmpAndDept" resultMap="empAndDeptResultMapTwo">
    14. select * from t_emp left join t_dept on t_emp.eid = t_dept.did where t_emp.eid = #{eid}
    15. </select>

    分步查询

  • select:设置分布查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)

  • column:设置分步查询的条件,通过哪个条件去查

    1.查询员工信息

    先查出员工信息,在根据员工的部门id,也就是did去查出部门的信息
    1. package com.lyd.mybatis.mapper;
    2. public interface EmpMapper {
    3. Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);
    4. }
    1. <resultMap id="empAndDeptByStepResultMap" type="Emp">
    2. <id property="eid" column="eid"></id>
    3. <result property="empName" column="emp_name"></result>
    4. <result property="age" column="age"></result>
    5. <result property="sex" column="sex"></result>
    6. <result property="email" column="email"></result>
    7. <association property="dept"
    8. select="com.lyd.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
    9. column="did">
    10. </association>
    11. </resultMap>
    12. <!--Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);-->
    13. <select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
    14. select * from t_emp where eid = #{eid}
    15. </select>

    2.查询部门信息

    1. package com.lyd.mybatis.mapper;
    2. public interface DeptMapper {
    3. Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);
    4. }
    1. <!--此处的resultMap仅是处理字段和属性的映射关系-->
    2. <resultMap id="EmpAndDeptByStepTwoResultMap" type="Dept">
    3. <id property="did" column="did"></id>
    4. <result property="deptName" column="dept_name"></result>
    5. </resultMap>
    6. <!--Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);-->
    7. <select id="getEmpAndDeptByStepTwo" resultMap="EmpAndDeptByStepTwoResultMap">
    8. select * from t_dept where did = #{did}
    9. </select>

    一对多映射处理

    一个部门,可以对应多个员工

使用collection处理映射关系

  • collection:用来处理一对多的映射关系
  • ofType:表示该属性对饮的集合中存储的数据的类型

    1. <resultMap id="DeptAndEmpResultMap" type="Dept">
    2. <id property="did" column="did"></id>
    3. <result property="deptName" column="dept_name"></result>
    4. <collection property="emps" ofType="Emp">
    5. <id property="eid" column="eid"></id>
    6. <result property="empName" column="emp_name"></result>
    7. <result property="age" column="age"></result>
    8. <result property="sex" column="sex"></result>
    9. <result property="email" column="email"></result>
    10. </collection>
    11. </resultMap>
    12. <!--Dept getDeptAndEmp(@Param("did") Integer did);-->
    13. <select id="getDeptAndEmp" resultMap="DeptAndEmpResultMap">
    14. select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
    15. </select>

    分步查询

    先查出部门信息,在根据部门id去查询学生,得到一个List

    1. 查询部门信息

    1. package com.lyd.mybatis.mapper;
    2. public interface DeptMapper {
    3. Dept getDeptAndEmpByStepOne(@Param("did") Integer did);
    4. }
    1. <resultMap id="DeptAndEmpByStepOneResultMap" type="Dept">
    2. <id property="did" column="did"></id>
    3. <result property="deptName" column="dept_name"></result>
    4. <collection property="emps"
    5. select="com.lyd.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
    6. column="did"></collection>
    7. </resultMap>
    8. <!--Dept getDeptAndEmpByStepOne(@Param("did") Integer did);-->
    9. <select id="getDeptAndEmpByStepOne" resultMap="DeptAndEmpByStepOneResultMap">
    10. select * from t_dept where did = #{did}
    11. </select>

    2. 根据部门id查询部门中的所有员工

    1. package com.lyd.mybatis.mapper;
    2. public interface EmpMapper {
    3. List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);
    4. }
    1. <!--List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);-->
    2. <select id="getDeptAndEmpByStepTwo" resultType="Emp">
    3. select * from t_emp where did = #{did}
    4. </select>

    延迟加载

    说到上面的分步查询,你可能会迷惑,这么麻烦干嘛。
    这就提现了延迟加载。
    什么是延迟加载,上面的多对一,查询员工信息和所在的部门信息,写成分步的方式,就可以使用延迟加载。开启了延迟加载,如果使用了员工对象里面的Dept对象,这时候才去执行第二步查询,查询部门信息。如果不用Dept对象,就不去查部门信息。
    如果有多个查询步骤,延迟加载是用什么,才去查什么。不用就不查。

    全局延时加载

  • 分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:

  • lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
  • aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载 。低版本的Mybatis好像是默认为true。需要手动设置为false。高版本的mybatis默认为false,不用设置。
  • 此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。
  • 此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType="lazy(延迟加载)|eager(立即加载)"

    1. <settings>
    2. <!--开启延迟加载-->
    3. <setting name="lazyLoadingEnabled" value="true"/>
    4. </settings>
    1. @Test
    2. public void getEmpAndDeptByStepOne() {
    3. SqlSession sqlSession = SqlSessionUtils.getSqlSession();
    4. EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    5. //上面的步骤封装过的,不全,运行不了,看个逻辑
    6. Emp emp = mapper.getEmpAndDeptByStepOne(1);
    7. System.out.println(emp.getEmpName());
    8. }

    看上面的java代码,用了分布查询,Emp emp = mapper.getEmpAndDeptByStepOne(1);得到了员工信息。emp.getEmpName()是获取员工名字,这时候使用了员工的数据。

  • 关闭延时加载,两条SQL都会运行(查询员工信息,查询部门信息)

image.png

  • 开启延时加载,值执行一条SQL,因为没有使用Dept对象

image.png
如果现在要使用Dept对象,emp.getDept()得到Dept部门信息,这时候使用延迟加载才会执行对应的SQL语句,注意执行的顺序

  1. @Test
  2. public void getEmpAndDeptByStepOne() {
  3. SqlSession sqlSession = SqlSessionUtils.getSqlSession();
  4. EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
  5. Emp emp = mapper.getEmpAndDeptByStepOne(1);
  6. System.out.println(emp.getEmpName());
  7. System.out.println("----------------");
  8. System.out.println(emp.getDept());
  9. }

image.png

fetchType

当开启了全局的延迟加载之后,可以通过该属性手动控制延迟加载的效果,fetchType="lazy(延迟加载)|eager(立即加载)"

  1. <resultMap id="empAndDeptByStepResultMap" type="Emp">
  2. <id property="eid" column="eid"></id>
  3. <result property="empName" column="emp_name"></result>
  4. <result property="age" column="age"></result>
  5. <result property="sex" column="sex"></result>
  6. <result property="email" column="email"></result>
  7. <association property="dept"
  8. select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
  9. column="did"
  10. fetchType="lazy">
  11. </association>
  12. </resultMap>