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 」欢迎转载,保留摘要,谢谢! 『 产品没有价值,开发团队再优秀也无济于事 – <启示录> 』 本文提纲 ...
随机推荐
- I/O等待事件-db file scattered read
摘自:http://blog.csdn.net/zq9017197/article/details/7925338
- PHP的重载-使用魔术方法实现
摘录PHP官网对PHP重载的解释: PHP所提供的"重载"(overloading)是指动态地"创建"类属性和方法.我们是通过魔术方法(magic method ...
- 《图解设计模式》读书笔记4-2 STRATEGY模式
目录 示例程序 角色 想法 Strategy模式即策略模式,在编程中,策略指的就是算法.利用此模式可以整体替换算法,即使用不同方式解决同一个问题.比如设计一个围棋程序,通过切换算法可以方便地切换AI的 ...
- Python程序打包为可执行文件exe
Python程序打包为可执行文件exe,pyinstaller应用 山重水复疑无路,柳暗花明又一村. 本来是向老师提交一个python程序,因为第一次所以就很尴尬只把源码给老师了,应该是打包成一个可执 ...
- 进程池Pool的简单使用,同步异步的区别
#进程池 """ 当需要创建子进程数量不多的时候,可以直接利用multiprocessing 中的Process动态生成多个进程,但是如果上百甚至上千个任务, " ...
- Postman初接触
https://www.getpostman.com/docs/postman/launching_postman/installation_and_updates
- oracle--用户区别sys和system
1.数据库的启动需要以SYSDBA/SYSOPER身份登录. 2.如果在同一主机上使用IPC连接到数据库使用操作系统授权,登录任何一个用户都可以拥有as sysdba和as sysoper. 3.sy ...
- ELK日志分析系统之logstash7.x最新版安装与配置
2 .Logstash的简介 2.1 logstash 介绍 LogStash由JRuby语言编写,基于消息(message-based)的简单架构,并运行在Java虚拟机(JVM)上.不同于分离的代 ...
- grep命令用关系或查询多个字符串
bcmsh ps | grep -E 'port|ge2 ' bcmsh ps | grep 'port\|ge2 ' 我的目的是筛选出含有 ‘port’ 或者含有 ‘ge2 ’ 的行,上面的第一行参 ...
- google+ sign in and get the oauth token 转摘:https://gist.github.com/ianbarber/5170508
package com.example.anothersignintest; import java.io.IOException; import com.google.android.gms ...