11.通常之路-缓存

MyBatis缓存介绍

正如大部分持久层框架一样,MyBatis 同样提供了拔尖缓存和二级缓存的支撑

  1. 一流缓存基于PerpetualCache 的 HashMap本地缓存,其储存功效域为
    Session,当 Session flush 或 close 之后,该Session中的全体 Cache
    就将清空。
  2. 二级缓存与一流缓存其编写制定一样,私下认可也是利用
    PerpetualCache,HashMap存款和储蓄,不一致在于其储存功效域为
    Mapper(Namespace),并且可自定义存款和储蓄源,如 Ehcache。
  3. 对此缓存数据更新机制,当某2个效用域(顶尖缓存Session/二级缓存Namespaces)的拓展了
    Create/Update/Delete 操作后,默许该意义域下全部 select
    中的缓存将被clear。

Mybatis的一级缓存

辉映文件

<mapper namespace="com.shxt.dao.UserDao">

     <resultMap type="com.shxt.model.User" id="BaseResultMapper">
        <id column="user_id" property="user_id"/>
        <result column="account" property="account"/>
        <result column="password" property="password"/>
        <result column="user_name" property="user_name"/>
        <result column="status" property="status"/>
        <result column="login_time" property="login_time"/>
        <result column="ip" property="ip"/>
        <result column="fk_role_id" property="fk_role_id"/>
    </resultMap>

    <sql id="sys_user_columns">
        user_id,account,password,user_name,status,login_time,ip,fk_role_id
    </sql>

    <select id="load" parameterType="int" resultMap="BaseResultMapper">
        SELECT
            <include refid="sys_user_columns"/>
        FROM
            sys_user
        WHERE user_id=#{user_id}
    </select>

</mapper>

询问 | 一流缓存测试

    @Test
    public void 查询_一级缓存测试(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.getSqlSession();

            User u1 = sqlSession.selectOne(UserDao.class.getName()+".load",-999);
            System.out.println("第一次查询:"+u1);

            User u2 = sqlSession.selectOne(UserDao.class.getName()+".load",-999);
            System.out.println("第二次查询:"+u2);

        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }

    }

操纵台运营结果表达

DEBUG [main] - ==>  Preparing: SELECT user_id,account,password,user_name,status,login_time,ip,fk_role_id FROM sys_user WHERE user_id=? 
DEBUG [main] - ==> Parameters: -999(Integer)
TRACE [main] - <==    Columns: user_id, account, password, user_name, status, login_time, ip, fk_role_id
TRACE [main] - <==        Row: -999, super, super, 刘文铭, 1, 2017-07-30 09:50:18.0, , -100
DEBUG [main] - <==      Total: 1
第一次查询:User [user_id=-999, account=super, password=super, user_name=刘文铭, status=1, login_time=Sun Jul 30 09:50:18 CST 2017, ip=, fk_role_id=-100]
第二次查询:User [user_id=-999, account=super, password=super, user_name=刘文铭, status=1, login_time=Sun Jul 30 09:50:18 CST 2017, ip=, fk_role_id=-100]

从上述结果中得以见到,两遍调用load方法,可是唯有三次查询数据库的进程,那种情况爆发的原由正是mybatis的一流缓存,并且一流缓存是暗中认可开启的。

查询-变更-查询 | 一流缓存测试

    @Test
    public void 查询_变更_一级缓存测试(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.getSqlSession();

            User u1 = sqlSession.selectOne(UserDao.class.getName()+".load",-999);
            System.out.println("第一次查询:"+u1);

            User u2 = new User();
            u2.setUser_id(-999);
            u2.setStatus(2);
            //变更数据库
            sqlSession.update(UserDao.class.getName()+".update", u2);

            User u3 = sqlSession.selectOne(UserDao.class.getName()+".load",-999);
            System.out.println("第二次查询:"+u3);

            //这里一定要提交,不然数据进不去数据库中
            sqlSession.commit();
        }catch (Exception ex) {
            ex.printStackTrace();
        }finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }

    }

一经中间经过中关系到CUD操作,那么缓存自动消失,重新查询

操纵台运转结果表明

DEBUG [main] - ==>  Preparing: SELECT user_id,account,password,user_name,status,login_time,ip,fk_role_id FROM sys_user WHERE user_id=? 
DEBUG [main] - ==> Parameters: -999(Integer)
TRACE [main] - <==    Columns: user_id, account, password, user_name, status, login_time, ip, fk_role_id
TRACE [main] - <==        Row: -999, super, super, 刘文铭, 1, 2017-07-30 09:50:18.0, , -100
DEBUG [main] - <==      Total: 1
第一次查询:User [user_id=-999, account=super, password=super, user_name=刘文铭, status=1, login_time=Sun Jul 30 09:50:18 CST 2017, ip=, fk_role_id=-100]
DEBUG [main] - ==>  Preparing: UPDATE sys_user SET status = ? WHERE user_id=? 
DEBUG [main] - ==> Parameters: 2(Integer), -999(Integer)
DEBUG [main] - <==    Updates: 1
DEBUG [main] - ==>  Preparing: SELECT user_id,account,password,user_name,status,login_time,ip,fk_role_id FROM sys_user WHERE user_id=? 
DEBUG [main] - ==> Parameters: -999(Integer)
TRACE [main] - <==    Columns: user_id, account, password, user_name, status, login_time, ip, fk_role_id
TRACE [main] - <==        Row: -999, super, super, 刘文铭, 2, 2017-07-30 09:50:18.0, , -100
DEBUG [main] - <==      Total: 1
第二次查询:User [user_id=-999, account=super, password=super, user_name=刘文铭, status=2, login_time=Sun Jul 30 09:50:18 CST 2017, ip=, fk_role_id=-100]

Mybatis的二级缓存

私下认可意况下是不曾打开Mybatis二级缓存的,那么笔者测试一下之类代码,看看运营效果

    @Test
    public void 查询_没有二级缓存测试(){
        //第一个SqlSession
        SqlSession sqlSession1 = null;
        //第二个SqlSession
        SqlSession sqlSession2 = null;
        try {
            sqlSession1 = MyBatisUtils.getSqlSession();

            sqlSession2 = MyBatisUtils.getSqlSession();

            User u1 = sqlSession1.selectOne(UserDao.class.getName()+".load",-999);
            System.out.println("sqlSession1 查询:"+u1);

            User u2 = sqlSession2.selectOne(UserDao.class.getName()+".load",-999);
            System.out.println("sqlSession2 查询:"+u2);

        } finally {
            MyBatisUtils.closeSqlSession(sqlSession1);
            MyBatisUtils.closeSqlSession(sqlSession2);
        }

    }

操纵台运转结果注明

DEBUG [main] - ==>  Preparing: SELECT user_id,account,password,user_name,status,login_time,ip,fk_role_id FROM sys_user WHERE user_id=? 
DEBUG [main] - ==> Parameters: -999(Integer)
TRACE [main] - <==    Columns: user_id, account, password, user_name, status, login_time, ip, fk_role_id
TRACE [main] - <==        Row: -999, super, super, 刘文铭, 2, 2017-07-30 09:50:18.0, , -100
DEBUG [main] - <==      Total: 1
sqlSession1 查询:User [user_id=-999, account=super, password=super, user_name=刘文铭, status=2, login_time=Sun Jul 30 09:50:18 CST 2017, ip=, fk_role_id=-100]
Tue Sep 05 16:20:42 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
DEBUG [main] - ==>  Preparing: SELECT user_id,account,password,user_name,status,login_time,ip,fk_role_id FROM sys_user WHERE user_id=? 
DEBUG [main] - ==> Parameters: -999(Integer)
TRACE [main] - <==    Columns: user_id, account, password, user_name, status, login_time, ip, fk_role_id
TRACE [main] - <==        Row: -999, super, super, 刘文铭, 2, 2017-07-30 09:50:18.0, , -100
DEBUG [main] - <==      Total: 1
sqlSession2 查询:User [user_id=-999, account=super, password=super, user_name=刘文铭, status=2, login_time=Sun Jul 30 09:50:18 CST 2017, ip=, fk_role_id=-100]

五个session,分别查询id为-999 的 User
,那么mybatis与数据库交互了一次,这样说明mybatis未来未曾拉开二级缓存,须求大家手动的拉开。

率先步:类别化持久化类

User.java类去完成Serializable接口,否则MyBatis的二级缓存不好用

public class User implements java.io.Serializable{
    private static final long serialVersionUID = 1L;
}

其次步:手动开启二级缓存

那里的标准化是,如若翻开了二级缓存,那么在闭馆sqlsession后,会把该sqlsession拔尖缓存中的数据增进到namespace的二级缓存中。

mybatis-config.xml配置音信

    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>

cacheEnabled的私下认可值正是true,所以能够忽略

UserMapper.xml开首二级缓存标签

<mapper namespace="com.shxt.dao.UserDao">
    <!-- 开启二级缓存 -->
    <cache></cache>
   <!-- 省略的部分代码  -->
</mapper>

其三步:测试代码

        @Test
    public void 查询_二级缓存测试() {
        // 第一个SqlSession
        SqlSession sqlSession1 = null;
        // 第二个SqlSession
        SqlSession sqlSession2 = null;

        sqlSession1 = MyBatisUtils.getSqlSession();

        sqlSession2 = MyBatisUtils.getSqlSession();

        User u1 = sqlSession1.selectOne(UserDao.class.getName() + ".load", -999);
        System.out.println("sqlSession1 查询:" + u1);
        MyBatisUtils.closeSqlSession(sqlSession1);// 关闭

        User u2 = sqlSession2.selectOne(UserDao.class.getName() + ".load", -999);
        System.out.println("sqlSession2 查询:" + u2);
        MyBatisUtils.closeSqlSession(sqlSession2);

    }

操纵台运维结果注解

DEBUG [main] - Cache Hit Ratio [com.shxt.dao.UserDao]: 0.0
DEBUG [main] - ==>  Preparing: SELECT user_id,account,password,user_name,status,login_time,ip,fk_role_id FROM sys_user WHERE user_id=? 
DEBUG [main] - ==> Parameters: -999(Integer)
TRACE [main] - <==    Columns: user_id, account, password, user_name, status, login_time, ip, fk_role_id
TRACE [main] - <==        Row: -999, super, super, 刘文铭, 2, 2017-07-30 09:50:18.0, , -100
DEBUG [main] - <==      Total: 1
sqlSession1 查询:User [user_id=-999, account=super, password=super, user_name=刘文铭, status=2, login_time=Sun Jul 30 09:50:18 CST 2017, ip=, fk_role_id=-100]
DEBUG [main] - Cache Hit Ratio [com.shxt.dao.UserDao]: 0.5
sqlSession2 查询:User [user_id=-999, account=super, password=super, user_name=刘文铭, status=2, login_time=Sun Jul 30 09:50:18 CST 2017, ip=, fk_role_id=-100]

在私下认可情状下,当sqlsession执行commit后会刷新缓存,那样的写法等价上边的写法

    @Test
    public void 查询_二级缓存测试(){
        //第一个SqlSession
        SqlSession sqlSession1 = null;
        //第二个SqlSession
        SqlSession sqlSession2 = null;
        try {
            sqlSession1 = MyBatisUtils.getSqlSession();

            sqlSession2 = MyBatisUtils.getSqlSession();

            User u1 = sqlSession1.selectOne(UserDao.class.getName()+".load",-999);
            System.out.println("sqlSession1 查询:"+u1);
            sqlSession1.commit();//强制刷新

            User u2 = sqlSession2.selectOne(UserDao.class.getName()+".load",-999);
            System.out.println("sqlSession2 查询:"+u2);

        } finally {
            MyBatisUtils.closeSqlSession(sqlSession1);
            MyBatisUtils.closeSqlSession(sqlSession2);
        }

    }

当为select语句时:

  • flushCache私下认可为false,表示别的时候语句被调用,都不会去清空本地缓存和二级缓存。
  • useCache默许为true,表示会将本条语句的结果开始展览二级缓存。

修改映射文件如下

<mapper namespace="com.shxt.dao.UserDao">
    <!-- 开启二级缓存 -->
    <cache></cache>


     <resultMap type="com.shxt.model.User" id="BaseResultMapper">
        <id column="user_id" property="user_id"/>
        <result column="account" property="account"/>
        <result column="password" property="password"/>
        <result column="user_name" property="user_name"/>
        <result column="status" property="status"/>
        <result column="login_time" property="login_time"/>
        <result column="ip" property="ip"/>
        <result column="fk_role_id" property="fk_role_id"/>
    </resultMap>

    <sql id="sys_user_columns">
        user_id,account,password,user_name,status,login_time,ip,fk_role_id
    </sql>
    <!-- 
    flushCache="true" 强制刷新

     -->
    <select id="load" parameterType="int" resultMap="BaseResultMapper" flushCache="true">
        SELECT
            <include refid="sys_user_columns"/>
        FROM
            sys_user
        WHERE user_id=#{user_id}
    </select>
</mapper>

再也运转从前commit的交由的测试方法 , 运营结果为:

DEBUG [main] - Cache Hit Ratio [com.shxt.dao.UserDao]: 0.0
DEBUG [main] - ==>  Preparing: SELECT user_id,account,password,user_name,status,login_time,ip,fk_role_id FROM sys_user WHERE user_id=? 
DEBUG [main] - ==> Parameters: -999(Integer)
TRACE [main] - <==    Columns: user_id, account, password, user_name, status, login_time, ip, fk_role_id
TRACE [main] - <==        Row: -999, super, super, 刘文铭, 2, 2017-07-30 09:50:18.0, , -100
DEBUG [main] - <==      Total: 1
sqlSession1 查询:User [user_id=-999, account=super, password=super, user_name=刘文铭, status=2, login_time=Sun Jul 30 09:50:18 CST 2017, ip=, fk_role_id=-100]
DEBUG [main] - Cache Hit Ratio [com.shxt.dao.UserDao]: 0.5
DEBUG [main] - ==>  Preparing: SELECT user_id,account,password,user_name,status,login_time,ip,fk_role_id FROM sys_user WHERE user_id=? 
DEBUG [main] - ==> Parameters: -999(Integer)
TRACE [main] - <==    Columns: user_id, account, password, user_name, status, login_time, ip, fk_role_id
TRACE [main] - <==        Row: -999, super, super, 刘文铭, 2, 2017-07-30 09:50:18.0, , -100
DEBUG [main] - <==      Total: 1
sqlSession2 查询:User [user_id=-999, account=super, password=super, user_name=刘文铭, status=2, login_time=Sun Jul 30 09:50:18 CST 2017, ip=, fk_role_id=-100]

当为insert、update、delete语句时:

  • flushCache暗中认可为true,表示别的时候语句被调用,都会招致当地缓存和二级缓存被清空。
  • useCache属性在本场馆下没有

总结

一流缓存

  1. 私下认可开启
  2. 非得同三个session,假如session对象已经close()过了就无法用了
  3. 询问条件必须一律
  4. 从未有过执行过session.cleanCache();清理缓存
  5. 并未履行过增加和删除改操作(那些操作都会清理缓存)

二级缓存

1.mybatis-config.xml 中暗许配置

<settings> 
        <setting name="cacheEnabled" value="true" /> 
</settings>

2.供给手动开启在Mapper.xml中添加

<mapper namespace="com.shxt.dao.UserDao">
    <!-- 开启二级缓存 -->
    <cache></cache>
     <resultMap type="com.shxt.model.User" id="BaseResultMapper">
        <id column="user_id" property="user_id"/>
        <result column="account" property="account"/>
        <result column="password" property="password"/>
        <result column="user_name" property="user_name"/>
        <result column="status" property="status"/>
        <result column="login_time" property="login_time"/>
        <result column="ip" property="ip"/>
        <result column="fk_role_id" property="fk_role_id"/>
    </resultMap>

    <sql id="sys_user_columns">
        user_id,account,password,user_name,status,login_time,ip,fk_role_id
    </sql>
    <!-- 
    flushCache="true" 强制刷新

     -->
    <select id="load" parameterType="int" resultMap="BaseResultMapper">
        SELECT
            <include refid="sys_user_columns"/>
        FROM
            sys_user
        WHERE user_id=#{user_id}
    </select>
</mapper>

3.映射语句文件中的全部select语句将会被缓存。
4.映射语句文件中的全部insert,update和delete语句会刷新缓存。
MyBatis,5.缓存会接纳Least Recently Used(LRU,近年来最少使用的)算法来收回。
6.缓存会遵照钦命的年华间隔来刷新。
7.缓存会蕴藏102陆个目的

<cache 
eviction="FIFO"  //回收策略为先进先出
flushInterval="60000" //自动刷新时间60s
size="512" //最多缓存512个引用对象
readOnly="true"/> //只读

说在前面包车型地铁话,个人感觉MyBatis的缓存意义一点都不大:
A. 面对一定范围的数据量,内置的cache情势就派不上用场了;
B. 对查询结果集做缓存并不是MyBatis框架擅长的,它专心做的应有是sql
mapper。采取此框架的Application去营造缓存更客观,比如利用OSCache、Memcached啥的。

网站地图xml地图