MyBatis框架核心之(八)Mybatis一级缓存与二级缓存以及自定义缓存

来源:互联网 发布:面膜种草知乎 编辑:程序博客网 时间:2024/06/16 22:12

五、Mybati缓存(一级缓存与二级缓存)

一、一级缓存

1.什么是一级缓存

一级缓存是SqlSession级别的缓存,是基于PerpetualCache的HashMap本地缓存。在操作数据库时需要构造sqlSession对象,在对象中有个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的SqlSession之间缓存数据区域 (HashMap)是互不影响的。

2.作用域

一级缓存的作用域是同一个SqlSession在同一个SqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据(前提是同一个session),将不再从数据库查询,从而提高查询效率。

(Mybatis默认开启一级缓存)

注意:

当 Session flush ,commit(执行插入、更新、删除),或 close 之后,该Session中的所有 Cache 就将清空。

 

代码实现(详细的代码会放在最后)

一级缓存的简单测试

//@Test

    public void firstGradeCache(){

        //获取一个session会话

        SqlSession session = getSession();

        //获取一个执行sql语句的映射接口   A

        MybatisCache firstGradeCacheA = session.getMapper(MybatisCache.class);

        //获取一个执行sql语句的映射接口   B

        MybatisCache firstGradeCacheB = session.getMapper(MybatisCache.class);

       

        //通过AB执行同一条sql

        Student studentA = firstGradeCacheA.queryStudentById(1);

        Student studentB = firstGradeCacheB.queryStudentById(1);

        //通过log4j发现sql语句执行了一次 ,并且两个对象相同。说明是第一次查询存入到内存里面的对象

        System.out.println(studentA==studentB);

       

    }

 

缓存数据更新机制

当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select中的缓存将被clear

//@Test

    public void firstGradeCacheCommit(){

        //获取一个session会话

        SqlSession session = getSession();

        //获取一个执行sql语句的映射接口   A

        MybatisCache firstGradeCacheA = session.getMapper(MybatisCache.class);

        //获取一个执行sql语句的映射接口   update

        MybatisCache update= session.getMapper(MybatisCache.class);

        //获取一个执行sql语句的映射接口   A

        MybatisCache firstGradeCacheB = session.getMapper(MybatisCache.class);

        //A先查询并获取实体1

        Student studentA = firstGradeCacheA.queryStudentById(1);

        //创建一个修改的数据

        Student updateStudent = new Student(1,"wahaha",2);

        //然后在用更新的执行接口修改一下数据

        update.updateStudent(updateStudent);

        //然后提交一下会话

        session.commit();

        //再查一下相同的用户

        Student studentB = firstGradeCacheB.queryStudentById(1);

        //会发现sql语句执行了两次,而且返回的对象也不是同一个地址了

        System.out.println(studentA==studentB);

       

    }

 

 

二、二级缓存

1.什么是二级缓存

 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache、Hazelcast等。

2. 作用域

二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace

不同的sqlSession多次执行相同namespace下的Sql语句第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。

二级缓存是跨SqlSession的

重点:因为mybatis默认一级缓存一直存在(为了数据的安全性考虑),所以说只有等session操作完成,并且close,或commit该session后(建议每次查询都记得关闭会话,commit使用不当的话会将所有缓存清空),查到的值才会存入到缓存中,供其他session使用

3.启用二级缓存

 

1).在核心配置文件Mybatis.xml中配置<setting>标签

(默认是开启的但是必须配置cache标签才能使用所以可以不配置)

属性

描述

允许值

默认值

cacheEnable

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

true/false

true

Mybatis.xml文件配置

<!-- 二级缓存的配置 -->

      <settings>

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

      </settings>

 

 

2).在Mapper.xml中开启二级缓存,当该namespace下的 sql执行完成会存储到它的缓存区域

(在mapper下第一行配置)

mapper.xml 文件配置

<mapper namespace="">   

<cache eviction="FIFO" flushInterval="10800000" size="512" readOnly="true" type="实现Cache接口的类"></cache>

      .........

</Mapper>

 

                

<cache>标签中的属性简介

1.   eviction 回收策略  (默认为 LRU)

【默认】LRU——最近最少使用的:移除最长时间不被使用的对象

【新】LFU——最近一段时间使用次数最少的(部分版本不能使用)

      FIFO——先进先出的:按对象进入缓存的顺序来移除他们

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

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

2.   flushInterval (刷新间隔)

      可以被设置为任意的正整数(60*60*1000这种形式是不允许的),而且它们代表一个合理的毫秒形式的时间段。

默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

3.size (引用数目)

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

4.readOnly (只读)

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

5.type  自定义缓存的类全类名

      自定义缓存需要实现cache接口,并且重写其中的方法,就可以使用第三方缓存了

代码实现

不使用提交,关闭和使用提交关闭

@Test

    public void secondGradeCacheNoCommitAndClose(){

       

        //获取一个session工厂

        SqlSessionFactory factory = getSqlSessionFactory();

        //获取两个不同的会话

        SqlSession sessionA = factory.openSession();

        SqlSession sessionB = factory.openSession();

        //执行接口

        MybatisCache firstGradeCacheA = sessionA.getMapper(MybatisCache.class);

        MybatisCache firstGradeCacheB= sessionB.getMapper(MybatisCache.class);

       

        //查询id1的学生

        Student studentA=firstGradeCacheA.queryStudentById(1);

        Student studentB=firstGradeCacheB.queryStudentById(1);

        //比较两个结果相同(如果是使用了序列化和反序列化则不相同)

        System.out.println(studentA==studentB);

       

        //如果不提交不关闭则数据一直在一级缓存中,会发起两个sql语句

    }

 

   

 

使用提交将数据存入二级缓存(注意如果是C/U/D操作后提交则会清空所有缓存)

@Test

    public void secondGradeCacheByCommit(){

       

        //获取一个session工厂

        SqlSessionFactory factory = getSqlSessionFactory();

        //获取两个不同的会话

        SqlSession sessionA = factory.openSession();

        SqlSession sessionB = factory.openSession();

        //执行接口

        MybatisCache firstGradeCacheA = sessionA.getMapper(MybatisCache.class);

        MybatisCache firstGradeCacheB= sessionB.getMapper(MybatisCache.class);

       

        //查询id1的学生

        Student studentA=firstGradeCacheA.queryStudentById(1);

        //关闭A会话,将一级缓存清空,存入二级缓存

        sessionA.commit();

        Student studentB=firstGradeCacheB.queryStudentById(1);

        //比较两个结果相同(如果是使用了序列化和反序列化则不相同)

        System.out.println(studentA==studentB);

        //通过log4j显示的运行结果可以看出语句值查询了一次

    }

 

   

使用关闭将数据存入二级缓存

@Test

    public void secondGradeCacheClose(){

       

        //获取一个session工厂

        SqlSessionFactory factory = getSqlSessionFactory();

        //获取两个不同的会话

        SqlSession sessionA = factory.openSession();

        SqlSession sessionB = factory.openSession();

        //执行接口

        MybatisCache firstGradeCacheA = sessionA.getMapper(MybatisCache.class);

        MybatisCache firstGradeCacheB= sessionB.getMapper(MybatisCache.class);

       

        //查询id1的学生

        Student studentA=firstGradeCacheA.queryStudentById(1);

        //关闭A会话,将一级缓存清空,存入二级缓存

        sessionA.close();

        Student studentB=firstGradeCacheB.queryStudentById(1);

        //比较两个结果相同(如果是使用了序列化和反序列化则不相同)

        System.out.println(studentA==studentB);

        //通过log4j显示的运行结果可以看出语句值查询了一次

    }

                  

 

 

 

三、自定义缓存的实现

(下面是mybatis使用Redis数据库作为自定义缓存的实例)


自定义缓存必须实现Cache接口,并且重写其中的方法才能使用

自定义缓存的实现

package cn.et.fuqiang.cache.xml;

 

import java.io.IOException;

import java.util.concurrent.locks.ReadWriteLock;

import java.util.concurrent.locks.ReentrantReadWriteLock;

 

import org.apache.ibatis.cache.Cache;

 

import redis.clients.jedis.Jedis;

 

public class RedisCache implements Cache {

       /**

        * 二级缓存是针对namespace的所以该id其实就是namespace

        */

       private String id;

       /**

        * 实现的是第三方缓存   redis

        * 使用Jedis

        */

       private Jedis jedis;

       /**

        * 定义构造器,当容器自动调用时会实例化并传入对应的值

        * @param id

        */

       public RedisCache(final String id){

              this.id=id;

              init();

       }

       /**

        * 初始化的连接方法

        */

       public void init(){

              jedis = new Jedis("localhost",6379);

       }

       /**

        * 返回namespace

        */

       public String getId() {

              return id;

       }

       /**

        * 将值存入redis中

        * 方法中使用了自定义的序列化方法,使用set(byte[] key,byte[] value)存入

        */

       public void putObject(Object key, Object value) {

             

              if(key==null || value==null){

                     return;

              }

              try {

                     //将值存入

                     jedis.set(SerializationUtil.objectToByte(key), SerializationUtil.objectToByte(value));

              } catch (IOException e) {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

              }

       }

       /**

        * 从redis中查找值

        * 方法中使用了自定义的反序列化方法,使用get(byte[] key)将值去除

        */

       public Object getObject(Object key) {

              if(key!=null){

                     try {

                            byte[] value = jedis.get(SerializationUtil.objectToByte(key));

                            if(value==null){

                                   return null;

                            }

                            return SerializationUtil.byteToObject(value);

                     } catch (IOException e) {

                            // TODO Auto-generated catch block

                            e.printStackTrace();

                     } catch (ClassNotFoundException e) {

                            // TODO Auto-generated catch block

                            e.printStackTrace();

                     }

              }

              return null;

       }

       /**

        * 用于从缓存中删除指定的键值

        */

       public Object removeObject(Object key) {

              if(key!=null){

                     try {

                            Object value = getObject(key);

                            jedis.del(SerializationUtil.objectToByte(key));

                            return value;

                     } catch (IOException e) {

                            // TODO Auto-generated catch block

                            e.printStackTrace();

                     }

              }

              return null;

       }

       /**

        * 清空所有缓存的方法

        */

       public void clear() {

              jedis.flushAll();

       }

      

       public int getSize() {

             

              return 0;

       }

       /**

        * 直接返回 ReadWriteLock的子类ReentrantReadWriteLock()实体

        */

       public ReadWriteLock getReadWriteLock() {

              return new ReentrantReadWriteLock();

       }

 

}

工具类SerializationUtil的代码

SerializationUtil 类

package cn.et.fuqiang.cache.xml;

 

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

 

public class SerializationUtil {

       /**

        * 序列化

        * @param object

        * @return

        * @throws IOException

        */

       public static byte[] objectToByte(Object object) throws IOException{

              /*

               * 使用一个byte数组输出流将数据以byte数组写入到内存中   使用out.toByteArray()将数组返回

               */

              ByteArrayOutputStream out = new ByteArrayOutputStream();

              ObjectOutputStream obj = new ObjectOutputStream(out);

              obj.writeObject(object);

              return out.toByteArray();

       }

      

       /**

        * 反序列化

        * @param data

        * @return

        * @throws IOException

        * @throws ClassNotFoundException

        */

       public static Object byteToObject(byte[] data) throws IOException, ClassNotFoundException{

              /*

               * 使用一个byte数组读取流  ,将数组读入到ByteArrayInputStream流中最后反序列化出去

               */

              ByteArrayInputStream inputStream = new ByteArrayInputStream(data);

              ObjectInputStream obj = new ObjectInputStream(inputStream);

              return obj.readObject();

       }

 

}

 

总结:一级缓存和二级缓存独有缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了C/U/D操作后,默认该作用域下所有select中的缓存将被clear

 

 

 

以上代码实例所有代码如下

1.Mybatis主配置文件

mybatis.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>

    <!-- 指定jdbc的配置文件位置 -->

    <propertiesresource="cn/et/fuqiang/cache/jdbc.properties"></properties>

    <!-- 二级缓存的配置 -->

    <settings>

       <settingname="cacheEnabled"value="true"/>

    </settings>

   

    <!-- 配置类别名 -->

    <typeAliases>

    <!-- 使用该标签将该包下的所有类统一起别名  默认为类名首字母小写           -->

       <packagename="cn.et.fuqiang.cache.entity"/>

    </typeAliases>

    <!-- 配置jdbc环境 -->

    <environmentsdefault="development">

       <environmentid="development">

           <transactionManagertype="JDBC"/>

           <!-- 配置数据库连接信息 -->

           <dataSourcetype="POOLED">

              <propertyname="driver"value="${driverClass}"/>

              <propertyname="url"value="${url}"/>

              <propertyname="username"value="${user}"/>

              <propertyname="password"value="${password}"/>

           </dataSource>

       </environment>

    </environments>

    <!-- 使用接口映射 配置查询语句 -->

    <mappers>

    <!-- 注册接口  如果使用的是注解则不需要mappers文件-->

       <!-- 有两种方式配置mapper

       第一种 如果有mapper.xml文件直接配置该文件

       <mapper resource="mapper 文件的类路径">

       第二种 配置接口的全类名

       重点:如果配置的是接口的全类名则mapper.xm文件的名字必须与接口名相同

       <mapper class="接口的全类名">

       -->

       <mapperresource="cn/et/fuqiang/cache/xml/StudentMapper.xml"/>

    </mappers>

 

</configuration>

 

2.接口映射的接口定义

package cn.et.fuqiang.cache.xml;

 

import cn.et.fuqiang.cache.entity.Student;

 

public interface MybatisCache {

   public Student queryStudentById(Integerstuid);

   public void updateStudent(Student student);

}

 

 

3.   接口对应的mapper配置文件

StudentMapper.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="cn.et.fuqiang.cache.xml.MybatisCache">

 

    <cache eviction="FIFO" flushInterval="10800000" size="512" readOnly="true" type="cn.et.fuqiang.cache.xml.RedisCache"></cache>

    <selectid="queryStudentById"resultType="student">

       select * from student where stuid=#{0}

    </select>

    <updateid="updateStudent">

       update student set stuname=#{stuname},gid=#{gid} where stuid=#{stuid}

    </update>

 

</mapper>

 

 

 

 

4.   实体类

Student 实体类

package cn.et.fuqiang.cache.entity;

 

import java.io.Serializable;

 

public class Student implements Serializable {

    /**

     *

     */

    private static final long serialVersionUID = 1L;

    private Integer stuid;//学生id

    private String stuname;//学生姓名

    private Integer gid;//班级id

    public Student() {}

    public Student(Integerstuid, String stuname, Integergid) {

       super();

       this.stuid =stuid;

       this.stuname =stuname;

       this.gid =gid;

    }

    public Integer getStuid() {

       return stuid;

    }

    public void setStuid(Integer stuid) {

        this.stuid =stuid;

    }

    public String getStuname() {

       return stuname;

    }

    public void setStuname(String stuname) {

       this.stuname =stuname;

    }

    public Integer getGid() {

       return gid;

    }

    public void setGid(Integer gid) {

       this.gid =gid;

    }

 

}

 

 

 

 

5.   测试运行的代码

MybatisCacheTest

package cn.et.fuqiang.cache.xml;

 

import java.io.InputStream;

 

import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.junit.Test;

 

import cn.et.fuqiang.cache.entity.Student;

 

 

public class MybatisCacheTest {

       public SqlSession getSession(){

              //mybatis的配置文件

        String resource = "mybatis.xml";

        //使用类加载器加载mybatis的配置文件(它也加载关联的映射文件)

        InputStream is = MybatisCacheTest.class.getResourceAsStream(resource);

        //构建sqlSession的工厂

        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);

        //使用MyBatis提供的Resources类加载mybatis的配置文件(它也加载关联的映射文件)

        //Reader reader = Resources.getResourceAsReader(resource);

        //构建sqlSession的工厂

        //SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);

        //创建能执行映射文件中sql的sqlSession

        return sessionFactory.openSession();

       }

       public SqlSessionFactory getSqlSessionFactory(){

              //mybatis的配置文件

        String resource = "mybatis.xml";

        //使用类加载器加载mybatis的配置文件(它也加载关联的映射文件)

        InputStream is = MybatisCacheTest.class.getResourceAsStream(resource);

        //构建sqlSession的工厂

        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);

        //使用MyBatis提供的Resources类加载mybatis的配置文件(它也加载关联的映射文件)

        //Reader reader = Resources.getResourceAsReader(resource);

        //构建sqlSession的工厂

        //SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);

        //创建能执行映射文件中sql的sqlSession

        return sessionFactory;

       }

       //@Test

       public void firstGradeCache(){

              /*

               一级缓存

               一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,

               在对象中有个(内存区域)数据结构(HashMap)用于存储缓存数据。

               不同的SqlSession之间缓存数据区域 (HashMap)是互不影响的。

               

               作用域

               一级缓存的作用域是同一个SqlSession在同一个SqlSession中两次执行相同的sql语句

               第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据,

               将不再从数据库查询,从而提高查询效率。当一个SqlSession结束后该SqlSession

               结束后该SqlSession中的一级缓存也就不存在了。(Mybatis默认开启一级缓存)

               */

              //获取一个session会话

              SqlSession session = getSession();

              //获取一个执行sql语句的映射接口   A

              MybatisCache firstGradeCacheA = session.getMapper(MybatisCache.class);

              //获取一个执行sql语句的映射接口   B

              MybatisCache firstGradeCacheB = session.getMapper(MybatisCache.class);

             

              //通过A和B执行同一条sql

              Student studentA = firstGradeCacheA.queryStudentById(1);

              Student studentB = firstGradeCacheB.queryStudentById(1);

              //通过log4j发现sql语句执行了一次  ,并且两个对象相同。说明是第一次查询存入到内存里面的对象

              System.out.println(studentA==studentB);

             

       }

      

       //@Test

       public void firstGradeCacheCommit(){

              /*

               一级缓存

               一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,

               在对象中有个(内存区域)数据结构(HashMap)用于存储缓存数据。

               不同的SqlSession之间缓存数据区域 (HashMap)是互不影响的。

               

               作用域

               一级缓存的作用域是同一个SqlSession在同一个SqlSession中两次执行相同的sql语句

               第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据(session在期间该session没有commit),

               将不再从数据库查询,从而提高查询效率。(Mybatis默认开启一级缓存)

               当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。

               

               注意:

                    如果SqlSession去执行commit操作(执行插入、更新、删除),

                    会清空SqlSession中的一级缓存,这样做的目的为了让缓存中的数据是最新的信息,避免脏读

               */

              //获取一个session会话

              SqlSession session = getSession();

              //获取一个执行sql语句的映射接口   A

              MybatisCache firstGradeCacheA = session.getMapper(MybatisCache.class);

              //获取一个执行sql语句的映射接口   update

              MybatisCache update= session.getMapper(MybatisCache.class);

              //获取一个执行sql语句的映射接口   A

              MybatisCache firstGradeCacheB = session.getMapper(MybatisCache.class);

              //让A先查询并 获取实体1

              Student studentA = firstGradeCacheA.queryStudentById(1);

              //创建一个修改的数据

              Student updateStudent = new Student(1,"wahaha",2);

              //然后在用更新的执行接口修改一下数据

              update.updateStudent(updateStudent);

              //然后提交一下会话

              session.commit();

              //再查一下相同的用户

              Student studentB = firstGradeCacheB.queryStudentById(1);

              //会发现sql语句执行了两次,而且返回的对象也不是同一个地址了

              System.out.println(studentA==studentB);

             

       }

       /**

        

       二级缓存

             二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,

        不同的sqlSession多次执行相同namespace下的Sql语句第一次执行完毕会将数据库中查询的数据写到缓存(内存),

        第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。

        所以说二级缓存是跨SqlSession的

       Mybatis默认是开启二级缓存的,但是需要在mapper.xml中配置cache标签才能使用。

       如果缓存中有数据就不用从数据库中获取,大大提高系统性能

       注意:

       要使用前一个session查询过的值,必须要等前一个session  关闭后才可以获取到

       否则该值还在一级缓存中,因为mybatis的一级缓存是默认的无法取消,这也是为了数据安全性考虑

      

        同一个SqlSessionFactory可以获取不同的session会话

        

        使用二级缓存

        1.在核心配置文件Mybatis.xml中配置<setting>标签

        (默认是开启的但是必须配置cache标签才能使用所以可以不配置该配置文件)

        <!-- 二级缓存的配置 -->

       <settings>

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

       </settings>

        2.在Mapper.xml中开启二级缓存,当该namespace下的 sql执行完成会存储到它的缓存区域

             在mapper下第一行配置

             <mapper namespace="">

             <!-- 配置二级缓存

              eviction 回收策略  默认为 LRU

                            【默认】LRU——最近最少使用的:移除最长时间不被使用的对象

                            【新】LFU——最近一段时间使用次数最少的(部分版本不能使用)

                           FIFO——先进先出的:按对象进入缓存的顺序来移除他们

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

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

              flushInterval (刷新间隔)

                            可以被设置为任意的正整数(60*60*1000这种形式是不允许的),而且它们代表一个合理的毫秒形式的时间段。

                            默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

              size (引用数目)

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

              readOnly (只读)

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

              type=""  自定义缓存的类

                            自定义缓存需要实现cache接口,并且重写其中的方法,就可以使用第三方缓存了

               -->

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

             

              .........

              </Mapper>

      

        */

       @Test

       public void secondGradeCacheNoCommitAndClose(){

             

              //获取一个session工厂

              SqlSessionFactory factory = getSqlSessionFactory();

              //获取两个不同的会话

              SqlSession sessionA = factory.openSession();

              SqlSession sessionB = factory.openSession();

              //执行接口

              MybatisCache firstGradeCacheA = sessionA.getMapper(MybatisCache.class);

              MybatisCache firstGradeCacheB= sessionB.getMapper(MybatisCache.class);

             

              //查询id为1的学生

              Student studentA=firstGradeCacheA.queryStudentById(1);

              Student studentB=firstGradeCacheB.queryStudentById(1);

              //比较两个结果相同(如果是使用了序列化和反序列化则不相同)

              System.out.println(studentA==studentB);

             

              //如果不提交不关闭则数据一直在一级缓存中,会发起两个sql语句

       }

       @Test

       public void secondGradeCacheByCommit(){

             

              //获取一个session工厂

              SqlSessionFactory factory = getSqlSessionFactory();

              //获取两个不同的会话

              SqlSession sessionA = factory.openSession();

              SqlSession sessionB = factory.openSession();

              //执行接口

              MybatisCache firstGradeCacheA = sessionA.getMapper(MybatisCache.class);

              MybatisCache firstGradeCacheB= sessionB.getMapper(MybatisCache.class);

             

              //查询id为1的学生

              Student studentA=firstGradeCacheA.queryStudentById(1);

              //关闭A会话,将一级缓存清空,存入二级缓存

              sessionA.commit();

              Student studentB=firstGradeCacheB.queryStudentById(1);

              //比较两个结果相同(如果是使用了序列化和反序列化则不相同)

              System.out.println(studentA==studentB);

              //通过log4j显示的运行结果可以看出语句值查询了一次

       }

       @Test

       public void secondGradeCacheClose(){

             

              //获取一个session工厂

              SqlSessionFactory factory = getSqlSessionFactory();

              //获取两个不同的会话

              SqlSession sessionA = factory.openSession();

              SqlSession sessionB = factory.openSession();

              //执行接口

              MybatisCache firstGradeCacheA = sessionA.getMapper(MybatisCache.class);

              MybatisCache firstGradeCacheB= sessionB.getMapper(MybatisCache.class);

             

              //查询id为1的学生

              Student studentA=firstGradeCacheA.queryStudentById(1);

              //关闭A会话,将一级缓存清空,存入二级缓存

              sessionA.close();

              Student studentB=firstGradeCacheB.queryStudentById(1);

              //比较两个结果相同(如果是使用了序列化和反序列化则不相同)

              System.out.println(studentA==studentB);

              //通过log4j显示的运行结果可以看出语句值查询了一次

       }

       @Test

       public void queryStudentRedis(){

              /**

               *使用二级缓存时前面的方法查询过该用户后,该方法查询直接从redis中获取,不发起sql语句

               */

              SqlSession session = getSession();

              MybatisCache firstGradeCache = session.getMapper(MybatisCache.class);

 

              Student student = firstGradeCache.queryStudentById(2);

              session.close();

       }

       /**

        * 提交一个数据看是否会将二级缓存清空

        */

       @Test

       public void commitData(){

              SqlSession session = getSession();

              MybatisCache update= session.getMapper(MybatisCache.class);

 

              Student updateStudent = new Student(1,"wahaha",2);

              update.updateStudent(updateStudent);

              session.commit();

       }

 

}

 

 

 

数据库的中的表可以根据实体的字段创建

自定义缓存类代码在上面,三、自定义缓存的实现中有代码

 

 

原创粉丝点击