mybatis笔记

111 阅读7分钟

MyBatis 学习笔记

简介:

  • 是一个基于java的持久层框架,支持自定义SQL,存储过程以及高级映射
  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO映射为数据库中记录
  • Mybatis是一个半自动的ORM框架

mybatis下载:

github.com/mybatis/myb…

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.25</version>
</dependency>

比较

  • JDBC:
    • SQL夹杂在java代码中,耦合度比较高,导致编码内伤
    • 维护不易且实际开发需求中SQL有变化,频繁修改的情况多见
    • 代码冗长,开发效率低
  • Hibernate和JPA
    • 操作简单,开发效率高
    • 程序中的长复杂的SQL需要绕过框架
    • 内部自动生产SQL,不容易做特殊持久化
    • 基于全映射的全自动框架,大量字段的POJO进行部分映射比较困难
    • 反射操作太多,导致数据库性能下降
  • Mybatis
    • 轻量级
    • SQL和java编码分开,功能边界清晰,java注重业务开发,SQL语句专注数据
    • 开发效率低于Hiberna,但是完全能够接收

创建核心配置文件

配置连接数据的信息,以及Mybatis的全局配置信息 映射文件中主要写SQL语句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis的约束-->
<!--根标签-->
<configuration>
    <!--environments连接数据库的环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--事务管理的方式-->
            <dataSource type="POOLED">
                <!--数据源-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/demo01"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
        <!--设置具体的环境-->
    </environments>
    <!--mappers:引入映射文件-->
    <mappers>
        <mapper resource="org/mybatis/example/BlogMapper.xml"/>
    </mappers>
</configuration>

步骤1、创建mapper接口

相当于dao接口,mapper仅仅是接口,没有实现类

public interface UserMapper {
    /*
    * Mybatis面向接口编程的两个一致
    * 1、namespace与Mapper接口的全类名一致
    * 2、映射文件中的SQL语句id和Mapper接口中的方法名一致
     */


    /*
    * 添加用户信息
    * */
    int insertUser();
    
    
}

步骤2、创建映射文件

ORM:对象关系映射:Java的实体类对象,关系型数据库,二者之间的对应关系。

  • 映射文件创建规则:表对应的实体类的类名+Mapper.xml,因此一个映射文件对应一个实体类,对应一张表的操作。
  • 映射文件: 1、namespace与Mapper接口的全类名一致 2、映射文件中的SQL语句id和Mapper接口中的方法名一致
<?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="Mapper.UserMapper">
   <insert id="insertUser">
        insert into t_user values (null,'admin','12345',23,'男','12345@qq.com')
   </insert>
</mapper>

步骤3:引入映射文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis的约束-->
<!--根标签-->
<configuration>
    <!--environments连接数据库的环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--事务管理的方式-->
            <dataSource type="POOLED">
                <!--数据源-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/demo01"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
        <!--设置具体的环境-->
    </environments>
    <!--mappers:引入映射文件-->
    <mappers>
        <mapper resource="Mapper/UserMapper.xml"/>
        <!--以路径的方式引入文件-->
    </mappers>
</configuration>

创建测试类

  • sqlsession:代表程序和数据库之间的绘画
  • sqlsessionFactory:是生产sqlsession的工厂
  • 工厂模式:如果创建一个对象,使用的过程基本固定,那么我们就可以把创建对象的相关代码封装到一个工厂类中,以后都使用这个工厂类进行生产我们需要的对象。
@Test
public void test01() throws IOException {
    //加载核心配置文件
    InputStream stream = Resources.getResourceAsStream("mybatis_config.xml");
    //获取sqlSessionFactoryBuilder
    SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
    //获取sqlsessionFactory
    SqlSessionFactory sqlSessionFactory = factoryBuilder.build(stream);
    //获取sqlsession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //获取mapper接口对象
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    //测试功能
    int i = mapper.insertUser();
    System.out.println(i);
}

提交事务,才会有效果:

System.out.println(i);
//提交事务
sqlSession.commit();

sqlsession默认不提交事务, 开启自动提交功能。 image.png

log4j日志

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd">
<log4j:configuration>
    <!--输出到控制台 -->
    <appender name="consoleAppender" class="org.apache.log4j.ConsoleAppender">
        <param name="Threshold" value="WARN" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" />
        </layout>
    </appender>

    <!--输出到文件(info) -->
    <!--将生成“info.log.2014-06-11”这样的日志文件 -->
    <appender name="fileAppenderInfo" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="${user.home}/logs/info.log" />
        <param name="DatePattern" value=".yyyy-MM-dd" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" />
        </layout>
        <filter class="org.apache.log4j.varia.LevelRangeFilter">
            <param name="LevelMin" value="INFO" />
            <param name="LevelMax" value="INFO" />
        </filter>
    </appender>

    <!--输出到文件(warn) -->
    <appender name="fileAppenderWarn" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="${user.home}/logs/warn.log" />
        <param name="DatePattern" value=".yyyy-MM-dd" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" />
        </layout>

        <filter class="org.apache.log4j.varia.LevelRangeFilter">
            <param name="LevelMin" value="WARN" />
            <param name="LevelMax" value="WARN" />
        </filter>
    </appender>

    <!--输出到文件(error) -->
    <appender name="fileAppenderError" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="${user.home}/logs/error.log" />
        <param name="DatePattern" value=".yyyy-MM-dd" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" />
        </layout>
        <filter class="org.apache.log4j.varia.LevelRangeFilter">
            <param name="LevelMin" value="ERROR" />
            <param name="LevelMax" value="ERROR" />
        </filter>
    </appender>

    <!--屏蔽所有org.springframework.*输出的Debug(及以下)信息 -->
    <logger name="org.springframework">
        <level value="INFO"></level>
    </logger>

    <root>
        <level value="ALL" />
        <appender-ref ref="consoleAppender" />
        <appender-ref ref="fileAppenderInfo" />
        <appender-ref ref="fileAppenderWarn" />
        <appender-ref ref="fileAppenderError" />
    </root>
</log4j:configuration>

测试查询功能:必须设置ResultType或者ResultMap

  • ResultType:结果类型,对应的实体类的对象。设置默认的映射关系
    通过字段名和属性名进行映射 image.png
  • ResultMap:结果映射,设置默认的自定义的关系
<select id="selectById" resultType="POJO.User">
    select * from t_user where id=1;
</select>

查询所有的返回list集合 image.png

核心配置文件

配置文件的顺序: properties、settings、typeAliases、typeHandlers、objectFactory、objectWrapperFactory、reflectorFactory、plugins、environments、databaseIdProvider、mappers

environment

配置多个连接数据库的环境

<!--environments连接数据库的环境-->
<environments default="development">
    <!--defualt:配置默认使用的环境的id-->
    
    <environment id="development">
        <!--id唯一标识,不能重复,表示当前连接的环境-->
        <transactionManager type="JDBC"/>
        <!--事务管理的方式:JDBC/Managed
        JDBC:表示操作数据库的时候,使用JDBC的原生的事务管理方式,事物的提交和回滚需要手动进行处理
        Managed:表示被管理,例如spring
        -->
        <dataSource type="POOLED">
            <!--
                数据源,type设置数据源的类型
                POOLED:使用数据库连接池缓存数据库连接
                UNPOOLED:不使用数据库连接池
                JNDI:使用上下文的数据源
            -->
            <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </dataSource>
    </environment>
    <!--设置具体的环境-->
</environments>
<!--mappers:引入映射文件-->

properties文件

编写properties文件 image.png 引入properties文件 image.png 读取properties文件数据 image.png


typeAliases 类型别名的功能

<!--设置类型别名-->
<!--通过类型代表全类名-->
<!--
    类型别名不区分大小写
    可以不设置alias:名字会设置为默认的类名,且不区分大小写
-->
<typeAliases>
    <typeAlias type="POJO.User" alias="User"/>
</typeAliases>
<typeAliases>
  <!--  <typeAlias type="POJO.User" alias="User"/>-->
    <!--以包为单位,将包下所有的类型设置为默认的类型别名,即类名且不区分大小写-->
    <package name="POJO"/>
</typeAliases>

mappers 引入映射文件

<mappers>
   <!-- <mapper resource="Mapper/UserMapper.xml"/>-->
    <!--以路径的方式引入文件-->
    
    <!--以包为单位引入-->
    <!--
        要求:
        mapper接口所在的包和映射文件所在的包一致
        mapper接口要和映射文件的名字一致
    -->
    <package name="Mapper"/>
</mappers>

image.png

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis的约束-->
<!--根标签-->
<configuration>
    <!--读取文件-->
    <properties resource="jdbc.properties"/>
    <!--设置类型别名-->
    <!--通过类型代表全类名-->
    <!--
        类型别名不区分大小写
        如果不设置alias:名字会设置为默认的类名,且不区分大小写
    -->
    <typeAliases>
      <!--  <typeAlias type="POJO.User" alias="User"/>-->
        <!--以包为单位,将包下所有的类型设置为默认的类型别名,即类名且不区分大小写-->
        <package name="POJO"/>
    </typeAliases>



    <!--environments连接数据库的环境-->
    <environments default="development">
        <!--defualt:配置默认使用的环境的id-->

        <environment id="development">
            <!--id唯一标识,不能重复,表示当前连接的环境-->
            <transactionManager type="JDBC"/>
            <!--事务管理的方式:JDBC/Managed
            JDBC:表示操作数据库的时候,使用JDBC的原生的事务管理方式,事物的提交和回滚需要手动进行处理
            Managed:表示被管理,例如spring
            -->
            <dataSource type="POOLED">
                <!--
                    数据源,type设置数据源的类型
                    POOLED:使用数据库连接池缓存数据库连接
                    UNPOOLED:不使用数据库连接池
                    JNDI:使用上下文的数据源
                -->
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
        <!--设置具体的环境-->
    </environments>
    <!--mappers:引入映射文件-->
    <mappers>
       <!-- <mapper resource="Mapper/UserMapper.xml"/>-->
        <!--以路径的方式引入文件-->
        
        <!--以包为单位引入-->
        <!--
            要求:
            mapper接口所在的包和映射文件所在的包一致
            mapper接口要和映射文件的名字一致
        -->
        <package name="Mapper"/>
    </mappers>
</configuration>

映射文件如何进行拼接(获取参数的两种方式)

  • 普通的JDBC
    • 字符串拼接:sql注入,操作麻烦
    • 占位符赋值:?,使用setString等方法为预编译的preparesStatement进行赋值,自动加上单引号,可以避免SQL注入
  • Mybatis
    • ${}:字符串拼接
    • #{}:占位符赋值 @Param标签

各种查询功能

  • 查询实体类对象,多条对象不能用实体类对象接收----toomanyResultException
  • 查询list集合.可以接收一条甚至为空的形式来进行接收
  • 聚合函数,分组函数:查询用户信息的总记录数,基本类型有默认的类型别名。
  • map集合:k-v:属性名对应属性值的形式;json对象;当有多个对象的时候,会有异常,当有多条数据的时候,要使用list集合
  • map集合可以存储多条数据,另外给他设定一个键,这样vlaue是一条数据,key不能重复
@MapKey("id")
Map<String,Object> getUserByIdToMap(@Param("id") Integer id);

mybatis特殊sql的执行(使用#会有问题)

#{}会自动添加一个‘’

  1. 模糊查询: 使用#{}时,sql语句,所以要使用${},或者进行手动的字符串拼接
select * from t_user where username like '%?%'
concat('%',#{username},'%')

最多的应用方式

"%"#{username}"%"
  1. 批量删除 如果使用#{id},会有单引号,所以我们应该直接使用${}
  2. 动态设计表名:将一张表拆分成多张表 这里的表名的拼接不可以使用${}
  3. 添加功能获取自增的主键:有一对多的关系,为一个表分配多的关系,eg,为学生设置班级id,useGeneratedKeys设置当前标签中的sql使用了自增的id,keyProperty将自增的组件的值赋值给传输到映射文件中,参数的某个属性。
ResultSet generatedKeys = insert.getGeneratedKeys();
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    insert into t_user values (null,#{username},#{password},#{age},#{sex},#{email})
</insert>

image.png

自定义映射ResultMap

  • 驼峰和下划线进行适配:如果直接使用resulttype进行返回类型,有不符合的时候---:三种方法
  • 为字段起别名
<select id="getAllEmp" resultType="emp">
    select eid,emp_name empName,age,sex,email from t_emp
</select>
  • 全局配置:将下划线自动映射成驼峰
<!--设置全局配置,作用与全部功能-->
<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
  • resultMap:设置自定义映射关系,id是唯一标识,type表示映射的那个实体类类型,id子标签设置主键的映射,result设置普通的映射,property设置映射关系中的实体类的属性名,column是设置映射关系中sql数据库的字段名。使用resultmap处理多对一的映射
<resultMap id="empResultMap" type="emp">
    <id property="eid" column="eid"></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>
</resultMap>
<select id="getAllEmp" resultMap="empResultMap">
    select * from t_emp
</select>

处理多对一的映射关系

- 级联属性赋值
<resultMap id="empAndDeptResultMapOne" type="emp">
    <id property="eid" column="eid"></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>
    <result property="dept.did" column="did"></result>
    <result property="dept.deptName" column="dept_name"></result>
</resultMap>
<select id="getEmpAndDept" resultMap="empAndDeptResultMapOne">
    select *
    from t_emp
             left join t_dept on t_emp.did = t_dept.did
    where t_emp.eid=#{eid};
</select>
- 第二种方式:association,专门用来处理多对一的映射关系,property表示需要处理的属性名(多的那个表)javatype这个属性的类型,通过反射获取赋值。
<association property="dept" javaType="Dept">
    <id property="did" column="did"></id>
    <result property="deptName" column="dept_name"></result>
</association>
  • 分步查询,用的多,associationselect:设置分步查询的sql的唯一标识,column:设置分步查询的条件
    职工接口中
/*
* 通过分步查询来获取
* 员工信息
* */
emp getEmpAndDeptByStepOne(@Param("eid") int eid);

在职工表

<resultMap id="getEmpAndDeptByStepOne" type="emp">
    <id property="eid" column="eid"></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>
    <association property="dept"
                 select="com.demo3.Mapper.DeptMapper.getEmpAndDeptByStepTwo"
                 column="did"></association>
                 
</resultMap>
<select id="getEmpAndDeptByStepOne" resultMap="getEmpAndDeptByStepOne">
    select * from t_emp where eid=#{eid}
</select>

在部门接口

Dept getEmpAndDeptByStepTwo(@Param("did") int did);

在部门表

<resultMap id="Two" type="Dept">
    <id property="did" column="did"></id>
    <result property="deptName" column="dept_name"></result>
</resultMap>
<select id="getEmpAndDeptByStepTwo" resultMap="Two">
    select * from t_dept where did = #{did}
</select>

延迟加载

分步查询可以实现延迟加载,默认不开启,必须在核心配置文件中设置全局信息

  • lazyLoadingEnable:延迟加载的全局开关,所有关联对象都会延迟加载
  • aggressiveLazyLoading:任何方法的调用都会加载该对象的所有属性,否则,每个属性按需加载。

处理一对多的关系

  • collection:用来处理一对多的关系,oftype:集合中存储的数据的类型
private List<emp> emps;

/*
* 获取部门以及部门对应的所有员工信息
* */
Dept getDeptAndEmps(@Param("did") int did);
<resultMap id="DeptAndEmps" type="Dept">
    <id property="did" column="did"></id>
    <result property="deptName" column="dept_name"></result>
    <collection property="emps" ofType="emp">
        <id property="eid" column="eid"></id>
        <result property="empName" column="emp_name"/>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"/>
        <result property="email" column="email"/>
    </collection>
</resultMap>
<select id="getDeptAndEmps" resultMap="DeptAndEmps">
    select * from t_dept left join t_emp on t_emp.did=t_dept.did where t_dept.did=#{did}
</select>
  • 分步查询 select:设置分步查询的sql的唯一标识,column设置查询的条件,fetchType:当开启全局的延迟加载之后,可通过这个属性手动控制延迟加载的效果。
Dept getDeptAndEmpsByStepOne(@Param("did") int did);
<select id="getDeptAndEmpsByStepOne" resultMap="one">
    select * from t_dept where did =#{did}
</select>

<resultMap id="one" type="Dept">
    <id property="did" column="did"></id>
    <result property="deptName" column="dept_name"></result>
    <collection property="emps" select="com.demo3.Mapper.EmpMapper.getDeptAndEmpByStepTwo" column="did"></collection>
</resultMap>
emp getDeptAndEmpByStepTwo(@Param("did") int did);
<select id="getDeptAndEmpByStepTwo" resultMap="two">
    select * from t_emp where did=#{did}
</select>
<resultMap id="two" type="emp">
    <id property="eid" column="eid"></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>
</resultMap>

动态SQL

定义:根据特定条件,动态拼接sql语句的功能。

if标签

1=1:可以更好的拼接关键字,并且不会出现sql语句无条件,使where错误的情况

  • if:根据test属性中的表达式,判断条件是否要进行拼接。
<select id="getEmpByCondition" 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!=' '">and age=#{age}</if>
    <if test="sex!=null and sex!=' '">and sex=#{sex}</if>
    <if test="email!=null and email!=' '">and email=#{email}</if>
</select>

where标签

当标签内有内容的时候,自动生成,当没有内容的时候,where标签不会自动生成该关键字,将内容前的多余的and,or去掉。不可以将内容后面的and,or去掉

<where>
<if test="empName != null and empName!= ' '"> and emp_name=#{empName}</if>
<if test="age!=null and age!=' '">and age=#{age}</if>
<if test="sex!=null and sex!=' '">and sex=#{sex}</if>
<if test="email!=null and email!=' '">and email=#{email}</if>
</where>

trim标签

  • prefix|suffix:将trim标签中内容前后添加指定内容
  • prefixOverrides|suffixOverrides:将trim标签中内容前后去掉指定内容
  • 若标签中没有内容时,没有任何效果。

choose,when,otherwise

当有一个条件成立,后面的语句就不会进行拼接,相当于if...else if

<where>
    <choose>
        <when test="empName!=null and empName!=' '">emp_name=#{empName}</when>
        <when test="age!=null and age!=' '">age=#{age}</when>
        <when test="sex!=null and sex!=' '">sex=#{sex}</when>
        <when test="email!=null and email!=' '">email=#{email}</when>
        <otherwise>
              eid=1
        </otherwise>
    </choose>
</where>

foreach标签

批量删除

int deleteMoreByArray(@Param("eids") int[] eids);
delete from t_emp where eid in
<foreach collection="eids" item="eid" separator="," open="(" close=")">
    #{eid}
</foreach>

批量添加

int insertMore(List<emp> list);
<insert id="insertMore">
    insert into t_emp values
     <foreach collection="emps" item="emp" separator=",">
           (null,#{emp.empName}...)
     </foreach>
                             
</insert>

sql标签

抽取常用的sql的公共字段

<sql id="empColums">eid,empname....</sql>
<select id="...">
    select <include refid="empColums"></include>
</select>

Mybatis的缓存

一级缓存

针对sqlsession级别,默认开启,同一个sqlsession查询相同数据,会有缓存,只对查询功能生效

一级缓存失效

  • 不同的sqlsession
  • 同一个sqlsession但是查询条件不同
  • 两次查询之间,实现了增删改操作
  • 同一个sqlsession两次查询期间手动清空了缓存(sqlsession.clearCache)

二级缓存

针对sqlSessionFactory级别,手动开启的,开启的条件

  • 在核心配置文件中,cacheEnable=true
  • 在映射文件中设置标签
  • 二级缓存只有在sqlsession关闭(close)或提交(commit)才会生效
  • 查询的数据所转换的实体类类型必须实现serializable接口 使二级缓存失效的情况: 两次查询之间执行任意的增删改,会使一二级缓存失效。

cache标签属性针对二级缓存

  • eviction:缓存回收策略:LRU,FIFO,SOFT,WEAK
  • flushinterval:刷新间隔,单位毫秒(默认,调用增删改时刷新)
  • size:引用数目,缓存存储多少对象
  • readOnly:只读缓存,二级缓存会给缓存对象的相同实例,这些对象不可修改,会造成数据库不一致的情况;读写缓存,返回缓存对象的拷贝,(通过序列化)。

缓存查询顺序

  • 先查询二级缓存,范围更大,命中率更高
  • 二级缓存未命中,再查询一级缓存
  • 一级缓存未命中,再查询数据库
  • sqlsession关闭之后,一级缓存中的数据会写入到二级缓存中。

mybatis整合第三方EHCache

代替二级缓存,cache中的type指定缓存技术

<!--mybatis ehcache整合包-->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>
<!--slf4j日志门面的一个具体实现-->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

mybatis的逆向工程

根据数据库表,由框架根据数据库表,反向生成实体类,mapper接口,mapper映射文件

分页插件的使用