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);
//通过A和B执行同一条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);
//查询id为1的学生
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);
//查询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显示的运行结果可以看出语句值查询了一次
}
三、自定义缓存的实现
(下面是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();
}
}
数据库的中的表可以根据实体的字段创建
自定义缓存类代码在上面,三、自定义缓存的实现中有代码
- MyBatis框架核心之(八)Mybatis一级缓存与二级缓存以及自定义缓存
- Mybatis一级缓存与二级缓存
- mybatis一级缓存、二级缓存和自定义二级缓存
- MyBatis一级缓存,二级缓存,自定义缓存
- 八、Mybatis一级缓存和二级缓存
- MyBatis之缓存(一级缓存、二级缓存)
- MyBatis一级缓存,二级缓存
- MyBatis 一级缓存,二级缓存
- mybatis一级缓存二级缓存
- MyBatis的一级缓存和二级缓存 以及 mybatis和ehcache缓存框架整合
- Mybatis学习笔记-一级缓存与二级缓存
- mybatis:一级缓存And二级缓存
- mybatis一级缓存和二级缓存
- MyBatis(4)一级缓存,二级缓存
- Mybatis 一级缓存和二级缓存
- MyBatis一级缓存和二级缓存
- mybatis 一级缓存和二级缓存
- Mybatis一级缓存和二级缓存
- 兄弟连学python》》》format格式字符串
- 云服务器发布踩坑
- shiro的使用详情
- redis主从配置
- angular路由 和过滤器分页加载数据
- MyBatis框架核心之(八)Mybatis一级缓存与二级缓存以及自定义缓存
- iscsi的基本设定
- python装饰器(decorator)
- 【Java消息中间件】Java消息中间件( 第3章 JMS规范 )
- class文件结构
- leetcode-134-Gas Station
- BZOJ1141: [POI2009]Slw
- 服务端实现分页效果的几种思路
- 计算机视觉大规模爆发,6大细分领域将撑起725亿元市场