mybatis基于xml方式整合二级缓存

首先,注意到,我们这里说的是基于xml的方式完成mybatis的二级缓存

1. mybatis全局开启二级缓存

  在mybatis-configration当中开启二级缓存

<!--开启二级缓存  -->
<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>

 

2. 在需要开启二级缓存的mapper文件当中指定cache标签

  

<!-- 开启二级缓存 -->
<cache></cache>

  其实这里可以配置<cache type="org.apache.ibatis.cache.impl.PerpetualCache"/>,PerpetualCache这个类是mybatis默认实现缓存功能的类。我们不写type就使用mybatis默认的缓存,也可以去实现 Cache 接口来自定义缓存。所以通过这句话,我们就知道跟ehcache的结合点就在这里。

 

3. 二级缓存内部实现:

  

  我们可以看到,二级缓存内部实际上也是一个hashMap

 

4. 额外的我们可能需要对实体类添加序列化接口

  

  开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中,如果我们要再取这个缓存的话,就需要反序列化了。所以mybatis中的pojo都去实现Serializable接口。

 

5. 代码实例 :

  5.1 创建一个自己的包

  

  5.2 configuration.xml 配置如下 : 

  

<?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">
<configuration>
    <!-- 注意dtd 是引用mybatis的,而不是sprinh的   -->

    <!-- 指定properties配置文件, 我这里面配置的是数据库相关 ,注意 文件夹路径,我这里存放的是同级的这里  -->
    <properties resource="resource.properties"></properties>

    <!-- 指定Mybatis使用log4j -->
    <settings>
        <setting name="logImpl" value="LOG4J" />
        <!-- <setting name="cacheEnabled" value="true" /> -->
    </settings>

    <environments default="development">
        <!-- 可以配置多个environment 来达到多数据源的配置,或者说能达到 生产、测试、开发环境的切换  -->
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <!-- 上面指定了数据库配置文件, 配置文件里面也是对应的这四个属性 一定要跟resource.properties当中的属性对应上 -->
                <property name="driver" value="${jdbc.driverClass}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.userName}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>

    <!-- 映射文件,mybatis精髓, 后面才会细讲  ,扫描mybatis的mapper映射文件,一定要放在resource文件夹下 -->
    <!--  mapper resource= 的值 必须是resource文件夹下的路径值  -->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
configuration.xml

  

<setting name="cacheEnabled" value="true" /> 注意到这句话在springboot应用当中可不加,springboot默认帮我们开启了,但是为了明确功能,我们还是加上吧,即便
是要去掉二级缓存,那我们就写false,上面我注释了,希望大家看得到。

  5.3 resource.properties 配置数据库信息

  

# 数据库配置文件
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/form?serverTimezone=UTC&useSSL=true&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&rewriteBatchedStatements=true
jdbc.userName=root
jdbc.password=root
# 我这里连接的是form本地库
resource.properties

  5.4 UserMapper 接口的编写

import org.apache.ibatis.annotations.Mapper;

import java.util.List;
import java.util.Map;

/**
 * @Auther: lxf
 * @Date: 2018/11/7 10:19
 * @Description:
 */
@Mapper
public interface UserMapper {

    Map<String,Object> findUserById(int id);

    List<Map<String,Object>> callProcTest(int dict_id);

    Map<String,Object> findUserByIdForCache(int id);

}
UserMapper.java

  5.5  main测试方法的编写 

   

public class TestMybatis {
    public static  void  main(String[] args) throws IOException {
        // testEhcache();
          testUserMapper();
         //  executeTest();
        // showEhcache();
    }
 public static void testUserMapper() throws IOException {
        SqlSessionFactory sessionFactory = null;
        String resource = "configuration.xml";
        sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource));   //从类路径中加载资源
        SqlSession sqlSessionOne = sessionFactory.openSession();
        SqlSession sqlSessionTwo = sessionFactory.openSession();
        SqlSession sqlSessionThree = sessionFactory.openSession();
        UserMapper userMapperOne = sqlSessionOne.getMapper(UserMapper.class);
        UserMapper userMapperTwo = sqlSessionTwo.getMapper(UserMapper.class);
        UserMapper userMapperThree = sqlSessionThree.getMapper(UserMapper.class);
        int id = 502;
        Map<String,Object> mapOne = userMapperOne.findUserByIdForCache(id);
        printMap(mapOne);
        mapOne = userMapperOne.findUserByIdForCache(id);
        printMap(mapOne);
        sqlSessionOne.commit();
        Map<String,Object> mapTwo = userMapperTwo.findUserByIdForCache(id);
        printMap(mapTwo);
        Map<String,Object> mapThree = userMapperThree.findUserByIdForCache(id);
        printMap(mapThree);
}

public static void printMap(Map<String,Object> map){
        for(String str : map.keySet()){
            System.out.println(str+"-->"+map.get(str));
        }
    }
}
main方法的编写

  5.6 UserMapper.xml的配置
  

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="UserMapper">

    <!-- 二级缓存+ ehcache 下面两个选一个就好,一个有日志,一个没有 -->
    <!--  type="org.mybatis.caches.ehcache.EhcacheCache"  -->
   <!-- <cache type="org.mybatis.caches.ehcache.LoggingEhcache"  />  -->
    <!-- 开启二级缓存  -->
    <cache></cache>

    <select id="findUserById" parameterType="int" resultType="Map">
        select user_id,user_name,CREATION_DATE from fnd_user where _id=#{id,jdbcType=INTEGER}
    </select>

    <!-- 测试能否执行存储过程  -->
    <select id="callProcTest" parameterType="int" resultType="Map" statementType="CALLABLE">
        { call myfuncdictproc2(#{p_dict_id,mode=IN,jdbcType=INTEGER}) }
    </select>

    <!-- useCache="false"  是用来禁止二级缓存的 -->
    <select id="findUserByIdForCache"  parameterType="int" resultType="Map" useCache="true">
      select user_id,user_name,CREATION_DATE from fnd_user where _id=#{id,jdbcType=INTEGER}
    </select>
</mapper> 

 


  

 

5.6 控制台查看最终显示结果

  

  可以看到二级缓存已经生效了。这里为什么是这样子的?可以看到我的代码当中第一次跟第二次是使用同一个sqlSession,然后才commit掉的,所以后面的2个都是二级缓存查询出来的,

 所以第三次查询打印是在二级缓存上命中了1次,是三分之一,第四次命中了2此,是二分之一;而第二次是1级缓存生效。

6. 额外注意事项

  6.1 useCache和flushCache

  mybatis中还可以配置userCache和flushCache等配置项,userCache是用来设置是否禁用二级缓存的,在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。

  

<select id="selectUserByUserId" useCache="false" resultType="com.ys.twocache.User" parameterType="int">
    select * from user where id=#{id}
</select>

  

  这种情况是针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存,直接从数据库中获取。 

  在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。

    设置statement配置中的flushCache=”true” 属性,默认情况下为true,即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。

  

<select id="selectUserByUserId" flushCache="true" useCache="false" resultType="com.ys.twocache.User" parameterType="int">
    select * from user where id=#{id}
</select>  <!--  不建议使用 flushCache="false" -->

  6.2 注意到多个sqlSession来做测试的时候,一定要知道 是上一个sqlSession  commit之后,才丢到缓存了,所以看我上面的main测试类,其他的sqlSession缓存名字是因为第一个sqlSession的查询

已经commit了,我们要知道使用的时机。

posted @ 2018-11-19 11:58  白云是世界的公民  阅读(640)  评论(0)    收藏  举报