mybatis整合redis二级缓存
mybatis默认开启了二级缓存功能,在mybatis主配置文件中,将cacheEnabled设置成false,则会关闭二级缓存功能
<settings>
<!--二级缓存默认开启,false关闭-->
<setting name="cacheEnabled" value="false" />
<!--mybatis日志打印到控制台-->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
mybatis框架虽然默认开启了二级缓存功能,但是并没有默认实现,也就是下面这句代码返回null, 然后走一级缓存

下面是配置Redis作为mybatis的二级缓存,代码如下:
(1)mybatis主配置文件mybatis-config.xml中添加如下配置
<settings>
<!--二级缓存默认开启,false关闭-->
<setting name="cacheEnabled" value="true" />
<!--mybatis日志打印到控制台,以便于观察-->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
(2)FemaleMapper.xml 配置如下
<mapper namespace="qinfeng.zheng.FemaleMapper">
<select id="getFemaleById" resultType="qinfeng.zheng.entity.Female" parameterType="int">
SELECT id,name FROM tb_female where id = #{id};
</select>
<cache eviction="LRU" type="qinfeng.zheng.RedisCache"/>
</mapper>
LRU是mybatis默认的过期策略
(3)qinfeng\zheng\RedisCache.java
import org.apache.ibatis.cache.Cache;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Map; /**
* 使用redis的Hash结构
*/
public class RedisCache implements Cache { private String id;
private JedisPool jedisPool;
private static int EXPIRE_TIME = 1000 * 1000; public RedisCache(String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
this.id = id;
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPool = new JedisPool(jedisPoolConfig, "192.168.79.221", 6379, 3000, "123456");
} @Override
public String getId() {
return id;
} @Override
public void putObject(Object key, Object value) {
execute(jedis -> {
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(stream);
outputStream.writeObject(value);
byte[] idBytes = id.getBytes();
jedis.hset(idBytes, key.toString().getBytes(), stream.toByteArray());
// 设置一个过期时间。。
if (jedis.ttl(idBytes) == -1) {
jedis.expire(idBytes, EXPIRE_TIME);
}
} catch (Exception e) {
throw new RuntimeException("put object to redis error!", e);
}
return null;
});
} @Override
public Object getObject(Object key) {
return execute(jedis -> {
try {
byte[] bytes = jedis.hget(id.getBytes(), key.toString().getBytes());
if (bytes == null) {
return null;
}
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
return objectInputStream.readObject();
} catch (Exception e) {
throw new RuntimeException("get data from redis error!", e);
}
});
} @Override
public Object removeObject(Object key) {
return execute(jedis -> jedis.hdel(id.getBytes(), key.toString().getBytes()));
} @Override
public void clear() {
execute(jedis -> jedis.del(id.getBytes())); //因为id是String类型,所以直接jedis.del(id)也行
} @Override
public int getSize() {
return (Integer) execute(jedis -> {
Map<byte[], byte[]> map = jedis.hgetAll(id.getBytes());
return map.size();
});
} private Object execute(RedisCallBack redisCallBack) {
try (Jedis jedis = jedisPool.getResource()) {
return redisCallBack.callBack(jedis);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}
public interface RedisCallBack {
Object callBack(Jedis jedis);
}
使用redis作为mybatis的二级缓存框架,最主要就是实现mybatis提供的spi接口--Cache即可,然后实现putObject,getObject这两个主要的方法即可。
除此之外,记得pom.xml文件中添加jedis依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
(4)修改测试代码
public class V1Test {
public static void main(String[] args) {
try (InputStream is = Resources.getResourceAsStream("mybatis-config.xml")) {
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
FemaleMapper femaleMapper = sqlSession.getMapper(FemaleMapper.class);
Female female = femaleMapper.getFemaleById(1);
System.out.println(female);
System.out.println("-----------分隔符----------------------------------");
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
FemaleMapper femaleMapper2 = sqlSession2.getMapper(FemaleMapper.class);
Female female2 = femaleMapper2.getFemaleById(1);
System.out.println(female2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
第一次运行:
Opening JDBC Connection
Created connection 331510866.
==> Preparing: SELECT id,name FROM tb_female where id = ?;
==> Parameters: 1(Integer)
<== Columns: id, name
<== Row: 1, soga
<== Total: 1
Female(id=1, name=soga)
-----------分隔符----------------------------------
Opening JDBC Connection
Created connection 1316061703.
==> Preparing: SELECT id,name FROM tb_female where id = ?;
==> Parameters: 1(Integer)
<== Columns: id, name
<== Row: 1, soga
<== Total: 1
Female(id=1, name=soga)
哈哈,貌似还是查库两次,redis缓存好像没有起到作用。
事实上,mybatis框架为二级缓存提供了一个缓冲Map, 需要在调用commit方法之后,才会将缓冲区Map中的数据写入到redis中。
我们修改一下测试代码,然后再运行观察结果
public class V1Test {
public static void main(String[] args) {
try (InputStream is = Resources.getResourceAsStream("mybatis-config.xml")) {
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
FemaleMapper femaleMapper = sqlSession.getMapper(FemaleMapper.class);
Female female = femaleMapper.getFemaleById(1);
System.out.println(female);
sqlSession.commit();
System.out.println("-----------分隔符----------------------------------");
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
FemaleMapper femaleMapper2 = sqlSession2.getMapper(FemaleMapper.class);
Female female2 = femaleMapper2.getFemaleById(1);
System.out.println(female2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
哎哎哎,报了个错,记得Female 需要序列化
Opening JDBC Connection
Created connection 490150701.
==> Preparing: SELECT id,name FROM tb_female where id = ?;
==> Parameters: 1(Integer)
<== Columns: id, name
<== Row: 1, soga
<== Total: 1
Female(id=1, name=soga)
-----------分隔符----------------------------------
Cache Hit Ratio [qinfeng.zheng.FemaleMapper]: 0.5
Female(id=1, name=soga)
请看,这次只查了一个库,第2冲直接缓存命中、
我们再运行一次刚才的代码
Cache Hit Ratio [qinfeng.zheng.FemaleMapper]: 1.0
Female(id=1, name=soga)
-----------分隔符----------------------------------
Cache Hit Ratio [qinfeng.zheng.FemaleMapper]: 1.0
Female(id=1, name=soga)
两次都缓存命中!!
再看一下redis:

好了, mybatis整合redis为二级缓存到此完毕,下章分析一下它的源码实现!
mybatis整合redis二级缓存的更多相关文章
- Mybatis使用Redis二级缓存
在Mybatis中允许开发者自定义自己的缓存,本文将使用Redis作为Mybatis的二级缓存.在Mybatis中定义二级缓存,需要如下配置: 1. MyBatis支持二级缓存的总开关:全局配置变量参 ...
- SpringBoot + MySQL + MyBatis 整合 Redis 实现缓存操作
本地安装 Redis Redis 安装:https://www.cnblogs.com/oukele/p/11373052.html 项目结构: SpringBootRedis 工程项目结构如下: ...
- SSM+redis整合(mybatis整合redis做二级缓存)
SSM:是Spring+Struts+Mybatis ,另外还使用了PageHelper 前言: 这里主要是利用redis去做mybatis的二级缓存,mybaits映射文件中所有的select都会刷 ...
- Spring Boot + Mybatis + Redis二级缓存开发指南
Spring Boot + Mybatis + Redis二级缓存开发指南 背景 Spring-Boot因其提供了各种开箱即用的插件,使得它成为了当今最为主流的Java Web开发框架之一.Mybat ...
- 【MyBatis学习13】MyBatis中的二级缓存
1. 二级缓存的原理 前面介绍了,mybatis中的二级缓存是mapper级别的缓存,值得注意的是,不同的mapper都有一个二级缓存,也就是说,不同的mapper之间的二级缓存是互不影响的.为了更加 ...
- Mybatis一级、二级缓存
Mybatis一级.二级缓存 一级缓存 首先做一个测试,创建一个mapper配置文件和mapper接口,我这里用了最简单的查询来演示. <mapper namespace="c ...
- Mybatis整合Redis实现二级缓存
Mybatis集成ehcache . 为什么需要缓存 拉高程序的性能 . 什么样的数据需要缓存 很少被修改或根本不改的数据 业务场景比如:耗时较高的统计分析sql.电话账单查询sql等 . ehcac ...
- springboot mybatis redis 二级缓存
前言 什么是mybatis二级缓存? 二级缓存是多个sqlsession共享的,其作用域是mapper的同一个namespace. 即,在不同的sqlsession中,相同的namespace下,相同 ...
- Spring Boot 整合 Redis 实现缓存操作
摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢! 『 产品没有价值,开发团队再优秀也无济于事 – <启示录> 』 本文提纲 ...
随机推荐
- bzoj 2002 Bounce 弹飞绵羊(分块)
2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 11202 Solved: 5698[Subm ...
- 16/7/11_PHP-数据库操作
PHP支持哪些数据库 PHP通过安装相应的扩展来实现数据库操作,现代应用程序的设计离不开数据库的应用,当前主流的数据库有MsSQL,MySQL,Sybase,Db2,Oracle,PostgreSQL ...
- JSP+JavaBean 登陆验证
1.java package cn.gs.ly; import java.util.HashMap; import java.util.Map; public class Register { pri ...
- composer的自动加载机制(autoload)
composer的出现真是让人们眼前一亮,web开发从此变成了一件很『好玩』的事情,开发一个CMS就像在搭积木,从packagist中取出『积木』搭建在自己的代码中,一点一点搭建出一个属于自己的王国. ...
- VS代码自动补全功能
VS代码自动补全功能 新建工程后,依次打开 工具>>代码段管理器>>选择C++>>点击 添加(A)...按钮 ,设置你的代码块的目录 复制以下代码并存为note.s ...
- flask项目中使用富文本编辑器
flask是一个用python编写的轻量级web框架,基于Werkzeug WSGI(WSGI: python的服务器网关接口)工具箱和Jinja2模板,因为它使用简单的核心,用extension增加 ...
- 1-for循环套生成器的面试题
参考自: https://www.cnblogs.com/shuimohei/p/9686578.html https://segmentfault.com/a/1190000016577353 题目 ...
- crack Tut.ReverseMe1.exe
测试文件:https://www.wocloud.com.cn/webclient/share/sindex.action?id=i9K_Br6TgE7ZLB3oBGUcJmKcRy5TUdZ8U6_ ...
- JSON —— 序列化与反序列化
1.JSON 反序列化 JSON 序列化:将服务器端的 JavaBean 对象转换成 JSON 字符串 JSON 反序列化:服务器端得到一个 JSON 字符串,然后将 JSON 字符串转换 JavaB ...
- linux系统部署war包,查看tomcat日志
1.部署war包app/tomcat/bin在tomcat/bin 目录下启动 .startup.sh,在启动过程中tomcat会对war包进行解压,形成相应的项目目录 执行命令:./startup. ...