mybatis学习教程中级(九)mybatis一级缓存、二级缓存(重点)

  1. 云栖社区>
  2. 博客>
  3. 正文

mybatis学习教程中级(九)mybatis一级缓存、二级缓存(重点)

ycy蓝码 2015-09-10 14:31:20 浏览504
展开阅读全文

1、前言

将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

看看我们常说说的缓存


这个就是我们常说的缓存,那么我们今天要看的肯定是mybatis缓存。

mybatis的缓存如下:

2、mybatis的一级缓存:


是sqlsession级别的缓存。就是你查询之后只要不commit(一般增删改才需要),就是不关闭sqlsession会话,就拥有缓存,mybatis默认支持一级缓存。

注意:如果与spring整合,我们还清楚的记得spring最后都要关闭sqlsession的,所以呀就不支持一级缓存了(虽然然并卵,但是还是值得我们学习一下)。

第一次发出一个查询sqlsql查询结果写入sqlsession的一级缓存中,缓存使用的数据结构是一个map<key,value>

keyhashcode+sql+sql输入参数+输出参数(sql的唯一标识)

value:用户信息

同一个sqlsession再次发出相同的sql,就从缓存中取不走数据库。如果两次中间出现commit操作(修改、添加、删除),本sqlsession中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存。



key里面部分数据:100881661:3415680886:com.ycy.mybatis.dao.UserMapper.getUserById:0:2147483647:SELECT  * FROM USER WHERE id=?:1:development

我们一直进入源码里面,进入execute里面去看看,因为我用的idea,进入源码看起来都吐了,没有Eclipse方便。没事可以看看,第二次他就读取这个key,那么久可以直接从原来的本地缓存读取。然后就这么完美的实现一级缓存。

实例:

package com.ycy.mybatis.test;

import com.ycy.mybatis.dao.OrdersCustomMapper;
import com.ycy.mybatis.dao.UserMapper;
import com.ycy.mybatis.dao.impl.UserMappermpl;
import com.ycy.mybatis.module.Orders;
import com.ycy.mybatis.module.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * Created by Administrator on 2015/8/31 0031.
 */
public class MybatisTest9 {
    private SqlSessionFactory sqlSessionFactory = null;
    @Before
    public void  before() throws IOException {
        String resource="SqlMapConfig.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        sqlSessionFactory= new SqlSessionFactoryBuilder().build(in);
    }
    //一级缓存测试
    @Test
    public  void findOrderAndDetail() throws Exception {
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //第一次查询
        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        User user= userMapper.getUserById(1);
        System.out.println(user.getUsername());
        //第二次查询(没有关闭sqlsession)
        User user2= userMapper.getUserById(1);
        System.out.println(user2.getUsername());
    }


}


3、mybatis二级缓存

是mapper级别缓存,垮sqlsession的。同一个namespace命名空间的缓存,以命名空间为单位来创建缓存结构。

如果从二级缓存没有取到,再从一级缓存中找,如果一级缓存也没有,从数据库查询。

map<keyvalue>


配置二级缓存:

3.1、打开总开关

 二级缓存

描述

允许值

默认值

cacheEnabled

对在此配置文件下的所有cache 进行全局性开/关设置。

true false

true

在setting里面增加
        <!-- 二级缓存总开关 -->
        <setting name="cacheEnabled" value="true"/>

3.2、mapper里面添加cache

要在你的Mapper映射文件中添加一行:  <cache /> ,表示此mapper开启二级缓存。在mapper下面增加

    <!--打开mapper二级缓存开关-->
    <cache/>



3.3、pojo中java对象需要实现序列化接口

public class User implements Serializable


3.4、测试结果

<span style="font-size:12px;">package com.ycy.mybatis.test;

import com.ycy.mybatis.dao.OrdersCustomMapper;
import com.ycy.mybatis.dao.UserMapper;
import com.ycy.mybatis.dao.impl.UserMappermpl;
import com.ycy.mybatis.module.Orders;
import com.ycy.mybatis.module.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * Created by Administrator on 2015/8/31 0031.
 */
public class MybatisTest9 {
    private SqlSessionFactory sqlSessionFactory = null;
    @Before
    public void  before() throws IOException {
        String resource="SqlMapConfig.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        sqlSessionFactory= new SqlSessionFactoryBuilder().build(in);
    }
    //一级缓存测试
    @Test
    public  void findOrderAndDetail() throws Exception {
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //第一次查询
        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        User user= userMapper.getUserById(1);
        System.out.println(user.getUsername());
        //第二次查询(没有关闭sqlsession)
        User user2= userMapper.getUserById(1);
        System.out.println(user2.getUsername());
    }
    //二级缓存测试
    @Test
    public  void cache2() throws Exception {
        SqlSession sqlSession=sqlSessionFactory.openSession();
        SqlSession sqlSession2=sqlSessionFactory.openSession();
        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        UserMapper userMapper2=sqlSession2.getMapper(UserMapper.class);

        //第一次查询
        User user= userMapper.getUserById(1);
        System.out.println(user.getUsername());
        sqlSession.close();

        //第二次查询()
        User user2= userMapper2.getUserById(1);
        System.out.println(user2.getUsername());

        sqlSession2.close();
    }

}</span>

我们主要看:这个表示缓存变为2次用了1次,0.5证明我们的缓存成功了哦

输出结果:

Cache Hit Ratio [com.ycy.mybatis.dao.UserMapper]: 0.5

17:35:47.516 [main] DEBUG com.ycy.mybatis.dao.UserMapper - Cache Hit Ratio [com.ycy.mybatis.dao.UserMapper]: 0.0
17:35:47.536 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Opening JDBC Connection
17:35:47.912 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Created connection 1674518905.
17:35:47.913 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@63cf2179]
17:35:47.917 [main] DEBUG com.ycy.mybatis.dao.UserMapper.getUserById - ==>  Preparing: SELECT * FROM USER WHERE id=? 
17:35:47.998 [main] DEBUG com.ycy.mybatis.dao.UserMapper.getUserById - ==> Parameters: 1(Integer)
17:35:48.024 [main] DEBUG com.ycy.mybatis.dao.UserMapper.getUserById - <==      Total: 1
王五
17:35:48.031 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@63cf2179]
17:35:48.032 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@63cf2179]
17:35:48.032 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Returned connection 1674518905 to pool.
17:35:48.033 [main] DEBUG com.ycy.mybatis.dao.UserMapper - Cache Hit Ratio [com.ycy.mybatis.dao.UserMapper]: 0.5
王五

3.5、二级缓存关闭

对于变化频率较高的sql,需要禁用二级缓存:(因为变得我们记住它没得意思)

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

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

    <select id="getUserById" parameterType="int" resultType="User" useCache="false">
         SELECT  * FROM USER WHERE id=#{id}
        </select>
不测试了哦,自己测试

如果你关闭之后去测试没有下面一行:

Cache Hit Ratio [com.ycy.mybatis.dao.UserMapper]: 0.0

3.6、刷新二级缓存

如果sqlsession操作commit操作,对二级缓存进行刷新(全局清空)。

设置statementflushCache是否刷新缓存,默认值是true

 <!--新增用户-->
    <insert id="insertUser" parameterType="User" flushCache="true">
        <!--插入值之后返回主键值-->
        <selectKey resultType="int" order="AFTER" keyProperty="id">
            SELECT LAST_INSERT_ID()
        </selectKey>
        INSERT  INTO USER  (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
    </insert>


不测试了哦,自己测试

你刷新之后,缓存依旧为0.0:

Cache Hit Ratio [com.ycy.mybatis.dao.UserMapper]: 0.0

3.7、 mybatiscache参数(了解)

 

mybatiscache参数只适用于mybatis维护缓存。

 

flushInterval:(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024

readOnly(只读)属性可以被设置为truefalse。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false

 

如下例子:

<cache  eviction="FIFO"  flushInterval="60000"  size="512"  readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有默认的是 LRU:

1. LRU  最近最少使用的:移除最长时间不被使用的对象。

2. FIFO  先进先出:按对象进入缓存的顺序来移除它们。

3. SOFT  软引用:移除基于垃圾回收器状态和软引用规则的对象。

4. WEAK  弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。



网友评论

登录后评论
0/500
评论
ycy蓝码
+ 关注