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 」欢迎转载,保留摘要,谢谢! 『 产品没有价值,开发团队再优秀也无济于事 – <启示录> 』 本文提纲 ...
随机推荐
- xpath定位不到原因浅析
在爬虫中,我们经常使用xpath来对元素进行定位,xpath定位分为两种,一种是绝对定位,/html/body/div[2]/div[1]/div/div[3]/a[7],另外一种是相对定位,比如r' ...
- ZOJ 3822 ( 2014牡丹江区域赛D题) (概率dp)
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5376 题意:每天往n*m的棋盘上放一颗棋子,求多少天能将棋盘的每行每列都至少有 ...
- JAVA一切皆对象之包装类、自动装箱、自动拆箱
首先封装一个基本数据类型int, class P{ private int number; //封装一个私有的->基本数据类型 public P(){} public P(int number) ...
- 【CDN+】 Kylin 的初步认识与理解
前言 项目中用到了Kylin框架来处理数据,那么作为项目成员需要了解哪些关于Kylin的知识呢,本文就Kylin得基本概念和原理进行简述. Kylin基本概念 首先想到的学习路径是Kylin官网: h ...
- Web安全测试——常见的威胁攻防
SQL注入 部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患.用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的SQL In ...
- Vagrant 手册之同步目录 - VirtualBox
原文地址 如果你使用的 provider 是 VirtualBox,那么 VirtualBox 同步目录就是默认的同步目录类型.这些同步目录使用 VirtualBox 的共享目录系统来同步客户机跟宿主 ...
- HTML--JS 多列求和
<html> <head> <title>多列求和</title> <script type="text/javascript" ...
- 终端参数上报后,平台通过tcp协议接收到相应数据并处理。
终端将终端参数以json格式的数据发送至平台.终端上电后上报,可以不认证直接上报. 实现流程如下. 1.设置终端参数上报的协议类型,例如:0x0000. public static final int ...
- Vue的入门之安装
vue.js是前端框架中比较热门的,因为工作关系,也加入了浩浩荡荡的学习大潮中,用笔记记录下点滴,便于后面学习查阅! 1 node.js环境的安装包(npm包管理器) 2 vue-cli 脚手架构建工 ...
- pjhp实现使用redis来存储session数据
#设置php处理session的方式为redis,并配置redis的访问地址(因为在redis中绑定的访问地址为127.0.0.1,所以就没有设置访问密码,如果需要请自行搜索)#因为不想修改php.i ...