当前位置:   article > 正文

映射器_auto-mapping-behavior

auto-mapping-behavior

一、select元素 - 查询语句

1、自动映射和驼峰映射

在setting元素中有两个可以配置的选项 autoMappingBehavior 和 mapUnderscoreToCamelCase,它们是控制自动映射和驼峰映射的开关。一般而言,自动映射会使用得多一点,因为可以通过SQL别名机制处理一些细节。
配置自动映射的autoMappingBehavior选项的取值范围是:

  • NONE,不进行自动映射
  • PARTIAL,默认值,只对没有嵌套结果集进行自动映射
  • FULL,对所有的结果集进行自动映射,包括嵌套结果集。
    在默认情况下,使用默认的PARTIAL级别的就可以了饿,为了实现自动映射,首先给出POJO——Role,如下:
package com.learn.ssm.pojo;

    private int id;

    private String roleName;

    private String note;
 
    /* getter and setter */
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

只要SQL列名和属性名保持一致,就会形成自动映射,比如通过角色编码(id)获取Role,如下代码:

<select id="getRole" parameterType="int" resultType="role">
        select id,role_name as roleName,note
        from t_role
        where id=#{id}
</select>
  • 1
  • 2
  • 3
  • 4
  • 5

这样就可以直接映射上去,无需做另外的配置,减少了工作量。
如果系统都严格按照驼峰命名法(比如,数据库的字段为role_Name,则POJO属性名为roleName;又如数据库字段为user_name,则POJO属性名为userName),那么只需要在配置把mapUnderscoreToCamelCase设置为true就行了。

2、传递多个参数

2.1使用map接口传递参数

在Mybatis中允许map接口通过键值对传递多个参数,把接口方法定义为:

    public List<Role> findRolesByMap(Map<String, Object> parameterMap);
  • 1
此时,传递给映射器的是一个map对象,使用它在sql中设置对应的参数,如下代码:
  • 1
<select id="findRoleByMap" parameterType="map" resultType="role">
        select id, role_name as roleName, note from t_role
        where role_name like concat('%', #{roleName}, '%'})
        and note like concat('%', #{note}, '%')
</select>
  • 1
  • 2
  • 3
  • 4
  • 5

注意,roleName和note是map的键,传递参数应该像是如下这样:


        RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
        Map<String, Object> map = new HashMap<>();
        map.put("roleName",1);
        map.put("note",1);
        List<Role> roleList = roleMapper.findRolesByMap(map);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
不推荐使用map传递参数,原因有二:
  • 1
  • map是一个键值对应的集合,使用者要通过阅读它的键,才能明了作用
  • map不能限定其传递参数的类型,所有业务性质不强

2.2、使用注解传递多个参数

MyBatis为开发者提供了一个注解Param,可以通过它去定义映射器的参数名称,使用它可以得到更好的可读性,将接口方法定义为:

    public List<Role> findRolesByAnnotation(@Param("roleName") String roleName, @Param("note") String note);
  • 1

    <select id="findRolesByAnnotation" resultType="role">
        select id, role_name as roleName, note
        from t_role
        where roleName like concat('%',#{roleName},'%')
        and note like concat('%',#{note},'%')
    </select>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意,此时不需要给出parameterType属性,让Mybatis自动探索就可以了。
通过改写使得可读性大大提高了,但是有一个麻烦:SQL很复杂,拥有大于十个参数,那么接口方法的参数个数也就多了,使用起来就很不容易,不过Mybatis还提供了JavaBean传递形式。

2.3、通过JavaBean传递多个参数

定义一个参数POJO —— RoleParams,如下:
  • 1
package com.learn.ssm.pojo.params;

public class RoleParams {
    private String roleName;
    
    private String note;

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
此时接口方法定义为:
  • 1
    public List<Role> findRolesByBean(RoleParams roleParams);
  • 1
<select id="findRolesByBean" parameterType="com.learn.ssm.pojo.params.RoleParams"
            resultType="role">
         select id, role_name as roleName, note
        from t_role
        where roleName like concat('%',#{roleName},'%')
        and note like concat('%',#{note},'%')
</select>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.3、混合使用

如果查询一个角色,可以通过角色名称和备注进行查询,与此同时还要支持分页,而分页的POJO如代码:

package com.learn.ssm.pojo.params;

public class PageParams {
    private int start;
    
    private int end;

    public int getStart() {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public int getEnd() {
        return end;
    }

    public void setEnd(int end) {
        this.end = end;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

这个时候的接口设计如下:

    public List<Role> findByMix(@Param("params") RoleParams roleParams, @Param("pags") PageParams pageParams);
  • 1
   <select id="findByMix" resultType="role">
        select id, role_name as roleName, note
        from t_role
        where role_name like concat('%', #{params.roleName}, '%')
        and note like concat('%', #{params.note},'%')
        limit #(page.start), #{page.limit}
    </select>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
这样就能使用混合参数了
  • 1

3、使用resultMap映射结果集:

<?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.learn.ssm.mapper.UserMapper">
    <resultMap id="userMapper" type="user">
        <result property="id" column="id"/>
        <result property="userName" column="user_name"/>
        <result property="password" column="password"/>
        <result property="sex" column="sex" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
        <result property="mobile" column="mobile"/>
        <result property="tel" column="tel"/>
        <result property="email" column="email"/>
        <result property="note" column="note"/>
    </resultMap>
    <select id="getUser" parameterType="long" resultMap="userMapper">
        select id,user_name,password,sex,mobile,tel,email,note
        from t_user
        where id=#{id}
    </select>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • resultMap定义了一个roleMap,id作为它的标识,type代表使用哪个类作为其映射的类,可以是别名或者全限定名
  • 它的子元素id代表resultMap的主键,而result代表着属性,id和result元素的property代表POJO属性的名称,column代表SQL的别名。
  • select元素中resultMap指定了采用哪个resultMap作为其映射规则

4、分页参数RowBounds

Mybatis 不仅支持分页,它还内置了一个专门处理分页的类:RowBounds,RowBounds源码如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.session;

public class RowBounds {
    public static final int NO_ROW_OFFSET = 0;
    public static final int NO_ROW_LIMIT = 2147483647;
    public static final RowBounds DEFAULT = new RowBounds();
    private int offset;
    private int limit;

    public RowBounds() {
        this.offset = 0;
        this.limit = 2147483647;
    }

    public RowBounds(int offset, int limit) {
        this.offset = offset;
        this.limit = limit;
    }

    public int getOffset() {
        return this.offset;
    }

    public int getLimit() {
        return this.limit;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
offset是偏移量,即从第几行开始记录,limit是限制条数,默认为0到java最大整数,使用非常简单,只要给接口增加一个RowBounds参数:
  • 1
    public List<Role> findByRowBounds(@Param("roleName") String roleName, @Param("note") String note, RowBounds rowBounds);
  • 1
 <select id="findByRowBounds" resultType="role">
        select id, role_name as roleName, note
        from t_role
        where role_name like concat('%', #{params.roleName}, '%')
        and note like concat('%', #{params.note},'%')
    </select>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注意,此时代码并没有任何关于分页的信息,但是Mybatis会自动识别它,使用如下代码进行测试:

package com.learn.ssm.chapter5;

import com.learn.ssm.mapper.RoleMapper;
import com.learn.ssm.pojo.Role;
import com.learn.ssm.utils.SqlSessionFactoryUtil;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class Main {
    public static void main(String[] args){
        String resource = "com/learn/ssm/chapter5/resource/mybatis-config.xml";
        SqlSession sqlSession = null;
        try{
            sqlSession = SqlSessionFactoryUtil.openSqlSession(resource);
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
            RowBounds rowBounds = new RowBounds(0,20);
            List<Role> roleList = roleMapper.findByRowBounds("role_name","note",rowBounds);
            System.out.println(roleList.size());
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(sqlSession != null){
                sqlSession.close();
            }
        }

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

二、insert元素 - 插入语句

1、简单的insert语句的应用

<insert id="insertRole" parameterType="role">
        insert into t_role(role_name,note)
        values (#{roleName},#{note})
</insert>
  • 1
  • 2
  • 3
  • 4

跟select元素大同小异

2、主键回填

有时候增加新用户的时候,首先会插入用户表的记录,然后插入用户和角色关系表,插入用户时如果没有办法拿到用户的主键,那么就没有办法插入用户和角色关系表了,因此在这个时候要拿到对应的主键。
JDBC中的Statement对象在只想插入的SQL后,可以通过getGeneratedKeys方法获得数据库生成的主键,这样便能达到获取主键的功能。在insert语句中有一个开关属性,userGenerateKeys,用来控制是否打开这个功能,它的默认值为false,当打开这个开关,还要配置其属性KeyProperty或者KeyColumn,告诉系统把生成的主键放入哪个属性,如果存在多个主键,则要用(。)分隔开

 <insert id="insertRole" parameterType="role"
          useGeneratedKeys="true" keyProperty="id">
      insert into t_role(role_name,note)
      values (#{roleName},#{note})
  </insert>
  • 1
  • 2
  • 3
  • 4
  • 5

useGeneratedKeys代表采用了JDBC的Statement对象的getGeneraterdKeys方法返回主键,而KeyProperty则代表用哪个POJO的属性,这里是id,说明它会用数据库生成的主键去赋值给这个POJO,测试主键回填:
image

3、自定义主键

有时候主键可能依赖于某些规则,比如取消角色表(t_role)的id递增规则,而将其修改:

  • 当角色表记录为空时,id设置为1
  • 当角色表记录不为空时,id设置为当前id加3
    MyBatis对这样场景提供了支持,主要依赖于selectKey元素进行支持,如下:
 <insert id="insertRole" parameterType="role">
        <selectKey keyProperty="id" resultType="long" order="BEFORE">
            select if(max(id) = null, 1, max((id) + 3) from t_role)
        </selectKey>
        insert into t_role(id,role_name,note)
        values (#{id},#{roleName},#{note})
</insert>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • keyProperty代表采用哪个属性作为主键
  • resultType返回一个long类型结果集
  • order设置为BEFORE标示将于当前定义的SQL前执行

三、update元素和delete元素

执行完返回一个整数,代表影响了数据库的行数,先来看看更新和删除角色表:
  • 1
     <delete id="deleteRole" parameterType="int">
        delete
        from t_role
        where id=#{id}
    </delete>
    <update id="updateRole" parameterType="role">
        update t_role
        set  role_name=#{roleName},note=#{note}
        where id=#{id}
    </update>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

四、sql元素

sql 元素的作用在于可以定义一条sql的一部分,方便后面的sql引用,如下所示:

  
    <sql id="roleCols">
        id, role_name as roleName, note
    </sql>
    <select id="getRole" parameterType="int" resultType="role">
        <!--select id,role_name as roleName,note -->
        select <include refid="roleCols"/>
        from t_role
        where id=#{id}
    </select>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

还支持变量传递:


    <sql id="roleCols">
        ${alias}.id, ${alias}.role_name,${alias}.note
    </sql>
    
    <select id="getRole" parameterType="long" resultMap="roleMap"
    select
    <include refid="roleCold">
        <property name="alias" value="r"/>
    </include>
        from t_role r where id = #{id}
    </select>
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

五、resultMap元素

resultMap的作用是定义映射规则,级联的更新,定制类型转化器等。resultMap定义的主要是一个结果集的映射关系,也就是SQL到JavaBean的映射关系定义,它也支持级联等特性。只是Mybatis现有的版本只支持resultMap查询,不支持更新或者保存。
  • 1

1、resultMap元素的构成

resultMap 元素的自元素,如代码:
  • 1
  <resultMap id="" type="">
        <constructor>
            <idArg/>
            <arg/>
        </constructor>
        <id/>
        <result/>
        <association/>
        <collection/>
        <discriminator javaType="">
            <case value=""></case>
        </discriminator>
    </resultMap>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

其中constructor元素用来配置构造方法,一个POJO可能不存在没有参数的构造方法,可以使用constructor进行配置。假设角色类RoleBean不存在没有参数的构造方法,它的构造方法声明为public RoleBean(Integer id, String roleName),那么需要配置结果集,如代码:

   <resultMap .....>
       <constructor>
           <idArg column="id" javaType="int"/>
           <arg column="role_name" javaType="string"/>
       </constructor>
   ...
   </resultMap>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
id 元素表示哪个列是主键,允许多个主键,多个主键则称为联合主键,result是配置POJO到SQL列名的映射关系。  
  • 1

2、使用map存储结果集

一般而言,任何select语句都可以使用map存储,如下代码:

    <select id="findColorByNote" parameterType="string" resultType="map">
        select id,color,note from t_color
        where note like concat('%','#{note}','%')
    </select>
  • 1
  • 2
  • 3
  • 4

使用map原则上是可以匹配所有结果集的,但是使用map接口就代表可读性下降,更多情况下会使用POJO方式。

3、使用POJO存储结果集

使用map方式就意味着可读性的丢失,POJO是最常用的方式。一方面可以使用自动映射,正如使用resultType属性一样,但是有时候需要更为复杂的映射或者级联,这个时候还可以使用select语句的resultMap属性配置映射集合,只是使用前要配置类似的resultMap,如代码:

   <resultMap id="roleResultMap" type="com.learn.ssm.pojo.Role">
      <id property="id" column="id"/>
      <result property="roleName" column="role_name"/>
      <result property="note" column="note"/>
  </resultMap>
  • 1
  • 2
  • 3
  • 4
  • 5

resultMap元素的属性id代表这个resultMap的标识,type代表要映射的pojo。
配置了resultMap之后就不允许在配置resultType

六、级联

1、建立POJO

++HealthForm.java++

package com.learn.ssm.pojo;

public abstract class HealthForm {
    private Long id;

    private Long empId;

    private String heart;

    private String liver;

    private String lung;

    private String kidney;

    private String note;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getEmpId() {
        return empId;
    }

    public void setEmpId(Long empId) {
        this.empId = empId;
    }

    public String getHeart() {
        return heart;
    }

    public void setHeart(String heart) {
        this.heart = heart;
    }

    public String getLiver() {
        return liver;
    }

    public void setLiver(String liver) {
        this.liver = liver;
    }

    public String getLung() {
        return lung;
    }

    public void setLung(String lung) {
        this.lung = lung;
    }

    public String getKidney() {
        return kidney;
    }

    public void setKidney(String kidney) {
        this.kidney = kidney;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

++FemaleHealthForm.java++

package com.learn.ssm.pojo;

public class FemaleHealthForm extends HealthForm {
    private String uterus;

    public String getUterus() {
        return uterus;
    }

    public void setUterus(String uterus) {
        this.uterus = uterus;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

++MaleHealthForm.java++

package com.learn.ssm.pojo;

public class MaleHealthForm {
    private String prostate;

    public String getProstate() {
        return prostate;
    }

    public void setProstate(String prostate) {
        this.prostate = prostate;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

员工表,工牌表和任务表的POJO,以员工表作为核心:
++WorkCard.java++

    package com.learn.ssm.pojo.params;

public class WordCard {
    private Long id;

    private Long empId;

    private String realName;
    
    private String department;
    
    private String mobile;
    
    private String position;
    
    private String note;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getEmpId() {
        return empId;
    }

    public void setEmpId(Long empId) {
        this.empId = empId;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

++Task.java++

package com.learn.ssm.pojo;

public class Task {
    private Long id;

    private String title;

    private String context;

    private String note;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContext() {
        return context;
    }

    public void setContext(String context) {
        this.context = context;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

++EmployeeTask.java++

package com.learn.ssm.pojo;

public class EmployeeTask {
    private Long id;

    private Long empId;

    private Task task = null;

    private String taskName;

    private String note;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getEmpId() {
        return empId;
    }

    public void setEmpId(Long empId) {
        this.empId = empId;
    }

    public Task getTask() {
        return task;
    }

    public void setTask(Task task) {
        this.task = task;
    }

    public String getTaskName() {
        return taskName;
    }

    public void setTaskName(String taskName) {
        this.taskName = taskName;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

++Employee.java++

package com.learn.ssm.pojo;

import com.learn.ssm.chapter4.Enum.SexEnum;

import java.util.Date;
import java.util.List;

public class Employee {
    private Long id;

    private String realName;

    private SexEnum sex = null;

    private Date birthday;

    private String mobile;

    private String email;

    private String position;

    private String note;

    private WordCard wordCard;

    private List<EmployeeTask> employeeTaskList = null;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public SexEnum getSex() {
        return sex;
    }

    public void setSex(SexEnum sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    public WordCard getWordCard() {
        return wordCard;
    }

    public void setWordCard(WordCard wordCard) {
        this.wordCard = wordCard;
    }

    public List<EmployeeTask> getEmployeeTaskList() {
        return employeeTaskList;
    }

    public void setEmployeeTaskList(List<EmployeeTask> employeeTaskList) {
        this.employeeTaskList = employeeTaskList;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109

++FemaleEmployee.java++

package com.learn.ssm.pojo;

public class FemaleEmployee extends Employee {
    private FemaleHealthForm femaleHealthForm = null;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

++MaleEmployee.java++

package com.learn.ssm.pojo;

public class MaleEmployee extends Employee {
    private MaleHealthForm maleHealthForm = null;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、配置映射文件

配置映射文件是级联的核心内容,Mapper不给出。
++TaskMapper.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.learn.ssm.mapper.TaskMapper">
    <select id="getTask" parameterType="long" resultMap="com.learn.ssm.pojo.Task">
        select id, title, context, note from t_task
        where id = #{id}
    </select>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

++WordCardMapper.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.learn.ssm.mapper.WordCardMapper">
    <select id="getWorkCardByEmpId" parameterType="long" resultType="com.learn.ssm.pojo.WordCard">
        select id,emp_id as empId,real_name as realName, department, mobile, position
        note
        from t_work_card
        where emp_id = #{empId}
    </select>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

z这样完成了两张映射文件。雇员任务表通过任务编号(task_id) 和任务表示关联,这是一个一对一的级联关系,使用association元素,雇员任务表一对一级联如下:

<?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.learn.ssm.mapper.EmployeeTaskMapper">
    <resultMap type="com.learn.ssm.pojo.EmployeeTask" id="EmployeeTaskMap">
        <id column="id" property="id"/>
        <result column="emp_id" property="empId"/>
        <result column="task_name" property="taskName"/>
        <result column="note" property="note"/>
        <association property="task" column="task_id"
                     select="com.learn.ssm.mapper.TaskMapper.getTask"/>
    </resultMap>

    <select id="getEmployeeTaskByEmpId" resultMap="EmployeeTaskMap">
        select id, emp_id, task_name, task_id, note
        from t_employee_task
        where emp_id = #{empID}
    </select>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

association代表着一对一级联的开始,property属性代表映射带POJO属性上。
体检表能拆分为男性和女性雇员,所以就有两个简单的映射器:

<?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.learn.ssm.mapper.MaleHealthFormMapper">
    <select id="getMaleHealthForm" parameterType="long" resultType="com.learn.ssm.pojo.MaleHealthForm">
        select id, heart, liver, spleen, lung, kidney, prostate, note
        from t_male_health_form
        where emp_id = #{id}
    </select>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
<?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.learn.ssm.mapper.FemaleHealthFormMapper">
    <select id="getFemaleHealthForm" parameterType="long" resultType="com.learn.ssm.pojo.FemaleHealthForm">
        select id, heart, liver, spleen, lung, kidney, uterus, note
        from t_female_health_form
        where emp_id = #{id}
    </select>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

下面代码创建雇员的映射关系,如代码:

<?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.learn.ssm.mapper.EmployeeMapper">
    <resultMap id="employee" type="com.learn.ssm.pojo.Employee">
        <id column="id" property="id"/>
        <result column="real_name" property="realName"/>
        <result column="sex" property="sex" typeHandler="com.learn.ssm.handler.SexEnumTypeHandler"/>
        <result column="birthday" property="birthday"/>
        <result column="mobile" property="mobile"/>
        <result column="email" property="email"/>
        <result column="position" property="position"/>
        <result column="note" property="note"/>
        <association property="wordCard" column="id" select="com.learn.ssm.mapper.WordCardMapper.getWordCardByEmpId"/>
        <collection property="employeeTaskList" column="id" select="com.learn.ssm.mapper.EmployeeTaskMapper.getEmployeeTaskByEmpId"/>
        <discriminator javaType="long" column="sex">
            <case value="1" resultMap="maleHealthFormMapper"/>
            <case value="0" resultMap="femaleHealthFormMapper"/>
        </discriminator>
    </resultMap>

    <resultMap id="femaleHealthFormMapper" type="com.learn.ssm.pojo.FemaleEmployee" extends="employee">
        <association property="femaleHealthForm" column="id"
                     select="com.learn.ssm.mapper.FemaleHealthFormMapper.getFemaleHealthForm"/>
    </resultMap>
    <resultMap id="maleHealthFormMapper" type="com.learn.ssm.pojo.MaleHealthForm" extends="employee">
        <association property="maleHealthForm" column="id" select="com.learn.ssm.mapper.MaleHealthFormMapper.getMaleHealthForm"/>
    </resultMap>
    <select id="getEmployee" parameterType="long" resultMap="employee">
        select id, real_name as realName, sex, birthday, mobile, email,position, note
        from t_employee where id=#{id}
    </select>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • association元素,对工牌进行一对一级联
  • collection,一对多级联,其select元素指向SQL,将通过column指定的Sql字段作为参数进行传递,然后将结果返回给雇员POJO属性employeeTaskList
  • discriminator元素,鉴别器,它的属性column代表使用哪个字段进行鉴别,这里是sex,它的子元素case,则用于区分,而resultMap属性表示采用哪个resultMap去映射,比如sex=1,则使用maleHealthFormMapper来映射。
    而对于雇员体检表而言,id为employee的resultMap,被maleHeanthFormMapper和femaleHealthFormMapper通过extends元素继承。
package com.learn.ssm.chapter5;

import com.learn.ssm.mapper.EmployeeMapper;
import com.learn.ssm.pojo.Employee;
import com.learn.ssm.utils.SqlSessionFactoryUtil;
import org.apache.ibatis.session.SqlSession;

public class Main {
    public static void main(String[] args){
        String resource = "com/learn/ssm/chapter5/resource/mybatis-config.xml";
        SqlSession sqlSession = null;
        try{
            sqlSession = SqlSessionFactoryUtil.openSqlSession(resource);
            sqlSession = SqlSessionFactoryUtil.openSqlSession(resource);
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
            Employee employee = employeeMapper.getEmployee(1L);
//            MaleHealthFormMapper mapper = sqlSession.getMapper(MaleHealthFormMapper.class);
//            mapper.getMaleHealthForm(1L);
            sqlSession.commit();
            System.out.println();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(sqlSession != null){
                sqlSession.close();
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

3、N + 1 问题

上面的级联已经成功,但是会引发性能问题:比如如果只想看到员工信息和员工任务信息,那么体验表和工牌的信息就是多余的,会让数据库多执行几条毫无疑义的SQL。
假设有N个关联关系完成了级联,那么只要再加入一个关联关系,就变成了N+1个级联,所有的级联SQL都会被执行,这样会造成浪费。Mybatis提供了延迟加载的技术

4、延迟加载

MyBatis的settings的配置有两个配置级联:
  • 1
配置项作用配置选项说明默认值
lazyLoadingEnabled延迟架子啊的全局开关。当开启时,所有关联对象都会延迟加载,在特定的关联关系中,可通过设置fetchType来覆盖该项的开关状态true、falsefalse
aggressiveLazyLoading当启用时,对任意延迟属性的调用会是带有延迟加载属性的对象完整加载;反之,则每种属性按需加载true、false版本3.4.1之前为true,之后为false

调整配置文件mybatis-config.xml

<settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
</settings>
  • 1
  • 2
  • 3
  • 4

运行代码,会发现先打印:

DEBUG 2019-05-21 20:20:10,507 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select id, real_name as realName, sex, birthday, mobile, email,position, note from t_employee where id=? 
DEBUG 2019-05-21 20:20:10,598 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Long)
DEBUG 2019-05-21 20:20:10,683 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ====>  Preparing: select id, heart, liver, spleen, lung, kidney, prostate, note from t_male_health_form where emp_id = ? 
DEBUG 2019-05-21 20:20:10,684 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ====> Parameters: 1(Long)
DEBUG 2019-05-21 20:20:10,685 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <====      Total: 1
DEBUG 2019-05-21 20:20:10,687 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后再打印:

DEBUG 2019-05-21 20:20:10,687 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select id, emp_id, task_name, task_id, note from t_employee_task where emp_id = ? 
DEBUG 2019-05-21 20:20:10,687 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2019-05-21 20:20:10,688 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 0
DEBUG 2019-05-21 20:20:10,688 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select id,emp_id as empId,real_name as realName, department, mobile, position note from t_work_card where emp_id = ? 
DEBUG 2019-05-21 20:20:10,689 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Long)
DEBUG 2019-05-21 20:20:10,689 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 0

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

从而得知,agressiveLazyLoading配置是一个层级开关,当设置为true,就开启了层级开关的加载,下面修改为false之后,打印日志:

DEBUG 2019-05-21 20:22:03,113 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7364985f]
DEBUG 2019-05-21 20:22:03,116 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select id, real_name as realName, sex, birthday, mobile, email,position, note from t_employee where id=? 
DEBUG 2019-05-21 20:22:03,170 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Long)
DEBUG 2019-05-21 20:22:03,255 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1
  • 1
  • 2
  • 3
  • 4

可以看出,只有雇员记录被查询出来。

选项lazeLoadingEnabled决定是否开启延迟加载,而选项aggressiveLazeLoading则控制是否采用层级加载,但是他们全都是全局配置,并不能解决需要,但是可以使用fetchType进行处理,fetchType出现在级联元素(association,collection,discriminator没有这个属性可配置),存在两个值:

  • eager,获得当前POJO之后立即加载对应的数据
  • lazy,获得当前POJO之后延迟加载对应的数据
    修改EmpolyeeMapper.xml:
    <collection property="employeeTaskList" column="id" select="com.learn.ssm.mapper.EmployeeTaskMapper.getEmployeeTaskByEmpId"
        fetchType="eager"/>
  • 1
  • 2

进行打印,得到日志:

UG 2019-05-21 20:29:01,861 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select id, real_name as realName, sex, birthday, mobile, email,position, note from t_employee where id=? 
DEBUG 2019-05-21 20:29:01,910 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Long)
DEBUG 2019-05-21 20:29:01,985 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ====>  Preparing: select id, emp_id, task_name, task_id, note from t_employee_task where emp_id = ? 
DEBUG 2019-05-21 20:29:01,985 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ====> Parameters: 1(Integer)
DEBUG 2019-05-21 20:29:01,986 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <====      Total: 0
DEBUG 2019-05-21 20:29:01,986 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5、多对多级联

两个一对多,形成多对多。

七、缓存

1、一级缓存和二级缓存

一级缓存是在SqlSession上的缓存,二级缓存实在SqlSessionFactory上的缓存。默认情况下,也就是没有任何配置的情况下,Mybatis会开启一级缓存,也就是对于SqlSession层面的缓存,这个缓存不需要POJO对象可序列化

++***测试一级缓存:***++

package com.learn.ssm.chapter5;

import com.learn.ssm.mapper.RoleMapper;
import com.learn.ssm.pojo.Role;
import com.learn.ssm.utils.SqlSessionFactoryUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

public class Main {
    public static void main(String[] args){
        String resource = "com/learn/ssm/chapter5/resource/mybatis-config.xml";
        Logger logger = Logger.getLogger(Main.class);

        SqlSession sqlSession = null;
        try{
            sqlSession = SqlSessionFactoryUtil.openSqlSession(resource);
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
            Role role = roleMapper.getRole(1);
            logger.info("再获取一次POJO.....");
            Role role2 = roleMapper.getRole(1);
        }catch (Exception e){
            logger.info(e.getMessage(), e);
            e.printStackTrace();
        }finally {
            if(sqlSession != null){
                sqlSession.close();
            }
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
DEBUG 2019-05-21 20:36:47,785 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 1935972447.
DEBUG 2019-05-21 20:36:47,786 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7364985f]
DEBUG 2019-05-21 20:36:47,791 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select id,role_name as roleName,note from t_role where id=? 
DEBUG 2019-05-21 20:36:47,830 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2019-05-21 20:36:47,879 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 0
 INFO 2019-05-21 20:36:47,879 com.learn.ssm.chapter5.Main: 再获取一次POJO.....
DEBUG 2019-05-21 20:36:47,879 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7364985f]
DEBUG 2019-05-21 20:36:47,891 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7364985f]
DEBUG 2019-05-21 20:36:47,891 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 1935972447 to pool.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

从日志上可以看出,虽然对同一对象进行了两次获取,但是实际上只有一条sql被执行,原因是代码使用了同一个SqlSession对象获取数据,当一个SqlSession第一个通过Sql和参数获取对象后,它会将其缓存起来,如果下次的Sql和参数都没有发生变化,并且缓存没有超市或者声明需要刷新时,那么他就会从缓存中获取数据.

package com.learn.ssm.chapter5;

import com.learn.ssm.mapper.RoleMapper;
import com.learn.ssm.pojo.Role;
import com.learn.ssm.utils.SqlSessionFactoryUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

public class Main {
    public static void main(String[] args){
        String resource = "com/learn/ssm/chapter5/resource/mybatis-config.xml";
        Logger logger = Logger.getLogger(Main.class);

        SqlSession sqlSession = null;
        SqlSession sqlSession1 = null;
        try{
            sqlSession = SqlSessionFactoryUtil.openSqlSession(resource);
            sqlSession1 = SqlSessionFactoryUtil.openSqlSession(resource);
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
            Role role = roleMapper.getRole(1);
            sqlSession.commit();
            logger.info("不同对象再获取一次POJO.....");
            RoleMapper roleMapper1 = sqlSession1.getMapper(RoleMapper.class);
            roleMapper1.getRole(1);
            sqlSession1.commit();
        }catch (Exception e){
            logger.info(e.getMessage(), e);
            e.printStackTrace();
        }finally {
            if(sqlSession != null){
                sqlSession.close();
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
DEBUG 2019-05-21 20:42:07,318 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7364985f]
DEBUG 2019-05-21 20:42:07,320 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select id,role_name as roleName,note from t_role where id=? 
DEBUG 2019-05-21 20:42:07,409 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2019-05-21 20:42:07,453 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 0
 INFO 2019-05-21 20:42:07,454 com.learn.ssm.chapter5.Main: 不同对象再获取一次POJO.....
DEBUG 2019-05-21 20:42:07,454 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Opening JDBC Connection
DEBUG 2019-05-21 20:42:07,461 org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 1210898719.
DEBUG 2019-05-21 20:42:07,462 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@482cd91f]
DEBUG 2019-05-21 20:42:07,462 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select id,role_name as roleName,note from t_role where id=? 
DEBUG 2019-05-21 20:42:07,464 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2019-05-21 20:42:07,465 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 0
DEBUG 2019-05-21 20:42:07,466 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7364985f]
DEBUG 2019-05-21 20:42:07,466 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7364985f]
DEBUG 2019-05-21 20:42:07,466 org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 1935972447 to pool.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

可以看出,Sql被执行的两次,这说明了一级缓存实在SqlSession层面上的,对于不同的SqlSession对象是不能共享的,开启二级缓存,只需要在映射文件(RoleMapper.xml)上加入代码

<cache/>
  • 1

这个时候Mybatis会序列化和反序列化对应的POJO,也就要求POJO是一个可序列化对象,那么就需要实现java.io.Serializable接口。
配置好,运行,得到日志:

DEBUG 2019-05-21 20:45:23,898 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d49af10]
DEBUG 2019-05-21 20:45:23,902 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select id,role_name as roleName,note from t_role where id=? 
DEBUG 2019-05-21 20:45:23,972 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Integer)
DEBUG 2019-05-21 20:45:24,019 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 0
 INFO 2019-05-21 20:45:24,033 com.learn.ssm.chapter5.Main: 不同对象再获取一次POJO.....
DEBUG 2019-05-21 20:45:24,038 org.apache.ibatis.cache.decorators.LoggingCache: Cache Hit Ratio [com.learn.ssm.mapper.RoleMapper]: 0.5
DEBUG 2019-05-21 20:45:24,038 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d49af10]
DEBUG 2019-05-21 20:45:24,039 org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d49af10]
DEBUG 2019-05-21 20:45
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2、缓存配置项,自定义和引用

属性说明取值备注
blocking是否使用阻塞性缓存,在读/写时他会加入JNI的锁进行操作true|false,默认值为false可保证读/写安全性,但加锁后性能不佳
readOnly缓存内容是否只读true|false,默认值为false如果为只读,则不会因为多个线程读/写造成不一致
eviction缓存策略,分为:
LRU最近最少使用的:移除最长时间不被使用的对象
FIFO先进先出:按对象进入缓存的顺序来移除它们
SOFT软引用:移除基于垃圾回收器状态和软引用规则的对象
WEAK弱引用:更积极移除基于垃圾收集器状态和弱引用规则的对象
默认值是LRU
flushInterval以毫秒为单位,如果1分钟刷新一次,则配置60000,默认为null,没有刷新时间,时候执行update,delete,insert才进行刷新
type自定义缓存类,要求实现org.apache.ibatis.cache.Cache
size缓存对象个数正整数,默认1024

对于其他语句,也可以这样:

<select ... flushCache="false" userCache="true"/>
  • 1

这是RoleMapper.xml的缓存配置,如果其他映射器也需要使用同样的配置,可以这样:

<cache-ref namespace=".....RoleMapper.xml"/>
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/438459
推荐阅读
相关标签
  

闽ICP备14008679号