缓存的作用就是降低数据库的使用率,来减轻数据库的负担。我们平常的操作一般都是查>改,所以数据库的有些查操作是重复的,如果一直使用数据库就会有负担。Mybatis也会做缓存,也会有一级缓存和二级缓存:

  • 一级缓存:是SqlSession级别的缓存,使用HashMap数据结构来用于存储缓存数据的
  • 二级缓存:是mapper级别的缓存,其作用域是mapper的同一个namespace,不同的SqlSession执行两次相同namespace下的sql语句,并且传递的参数相同,返回的结果也相同时,第一次执行sql语句是会将数据从数据库中取出并存入缓存中,第二次查询时便会从缓存中直接获取数据
    二级缓存的实现大大的降低了数据库的负担,这里就来实现以下使用redis实现Mybatis的二级缓存。

我这里使用springboot快速搭建的项目>>>直通<<<,基本的环境如下:
jdk 1.7+
springboot maven mybatis项目
redis
mysql

二级缓存的实现

概述

redis二级缓存的实现,主要是重写了Cache.java的方法,自定义缓存,先来看看Cache的方法有哪些:

1
2
3
4
5
6
7
String getId();
void putObject(Object var1, Object var2);
Object getObject(Object var1);
Object removeObject(Object var1);
void clear();
int getSize();
ReadWriteLock getReadWriteLock();

这里有put、get、clear等方法,将在我们自己的缓存方法中重写这些方法

自定义缓存方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
public class implements Cache {
private static final Logger logger = LoggerFactory.getLogger(MybatisRedisCache.class);
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private RedisTemplate redisTemplate;
private String id;
private static final long EXPIRE_TIME_IN_MINUTES = 30;
public (String id){
if (id==null){
throw new IllegalArgumentException("Cache instances require an ID");
}
logger.info("=====================================Redis cache id = "+id);
this.id = id;
}
public String getId() {
return id;
}
public void putObject(Object key, Object value) {
logger.debug("==============================redis put= "+key);
RedisTemplate redisTemplate = getRedisTemplate();
ValueOperations opsForValue = redisTemplate.opsForValue();
opsForValue.set(key, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES);
}
public Object getObject(Object key) {
logger.debug("================================redis get================================");
RedisTemplate redisTemplate = getRedisTemplate();
ValueOperations opsForValue = redisTemplate.opsForValue();
return opsForValue.get(key);
}
public Object removeObject(Object key) {
logger.debug("==========================================redis remove==========================");
RedisTemplate redisTemplate = getRedisTemplate();
redisTemplate.delete(key);
return null;
}
public void clear() {
logger.debug("=====================================clear redis================================");
RedisTemplate redisTemplate = getRedisTemplate();
redisTemplate.execute(new RedisCallback() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
大专栏  redis实现二级缓存
connection.flushDb();
return "OK";
}
});
}
@Override
public int getSize() {
return 0;
}
@Override
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
public RedisTemplate getRedisTemplate() {
if (redisTemplate == null) {
redisTemplate = ApplicationContextHolder.getBean("redisTemplate");
}
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
}

这里需要用到redisTemplate,一开始我们初始化的是空的redisTemplate,这样的话redisTemplate.opsForValue()就是一个空指针异常,所以我们这里要getBean来获取,所以这里有一个ApplicationContextHolder工具类。

ApplicationContextHolder.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
applicationContext = ctx;
}
/**
* Get application context from everywhere
*
* @return
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* Get bean by class
*
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
/**
* Get bean by class name
*
* @param name
* @param <T>
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
}

二级缓存的使用

在mapper中添加自定义cache:

1
<cache type="com.yif.utils.MybatisRedisCache" eviction="LRU"/>

其中的eviction有4个不同的参数:

LRU :最近最少使用的:移除最长时间不被使用的对象
FIFO:先进先出:按进入缓存的顺序来移除他们
SOFT:软引用:移除基于垃圾回收器状态和软引用规则的对象
WEAK:弱引用:更积极的移除基于垃圾收集器状态和弱引用规则的对象

测试

测试前先在数据库中插入几条数据,用户测试二级缓存,其实二级缓存就是在原先完整的数据库操作程序中添加了一个自定义cache并在数据库mapper中引入使用。
1.启动redis,查看redis中的keys,可以看到现在是空的

2.启动程序,首先会运行MybatisRedisCache中的构造函数,在日志中看到id=com.yif.redis.model.User,即你的实例

3.运行查询步骤,MybatisRedisCache的运行顺序是:
第一次查询:
getObject()–>putObject()–>数据库查询

再看看redis中的keys,可以看出已经将存入了一个新的key

第二次相同的查询:
getObject()

这样就可以看出第一次查询是从数据库中查出然后将结果存入缓存中,第二次相同的查询是从缓存中就查出了,不再通过数据库查询。

注意:

在mapper文件中,主要两个参数:flushCache和useCache:

在select中,flushCache默认是false,不会清除本地缓存和二级缓存;useCache默认为true,表示进行二级缓存
在update、insert和delete中,flushCache默认为true,会清空本地缓存和二级缓存;而useCache在此是不存在的

所以在update语句中加上flushCache后更新数据库会清除redis的二级缓存,这样在进行下一次查询时,从redis中获取的便是自动更新后的数据(会将数据库的数据put到redis中),这里还有一个情况,也是自己遇到的。网上有很多资料写着MybatisRedisCache中的clear()方法是无用的,所以很多都没有写,这里我也没写,不过这样的话更新后就不会自动更新,所以自己又写了clear()方法,在数据库更新之后便会执行这个clear()方法。

redis实现二级缓存的更多相关文章

  1. SpringMVC + MyBatis + Mysql + Redis(作为二级缓存) 配置

    2016年03月03日 10:37:47 标签: mysql / redis / mybatis / spring mvc / spring 33805 项目环境: 在SpringMVC + MyBa ...

  2. MySQL与Redis实现二级缓存

    redis简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库 Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的持久化, ...

  3. mybatis plus使用redis作为二级缓存

    建议缓存放到 service 层,你可以自定义自己的 BaseServiceImpl 重写注解父类方法,继承自己的实现.为了方便,这里我们将缓存放到mapper层.mybatis-plus整合redi ...

  4. mybatis 使用redis实现二级缓存(spring boot)

    mybatis 自定义redis做二级缓存 前言 如果关注功能实现,可以直接看功能实现部分 何时使用二级缓存 一个宗旨---不常变的稳定而常用的 一级是默认开启的sqlsession级别的. 只在单表 ...

  5. SpringMVC +Spring + MyBatis + Mysql + Redis(作为二级缓存) 配置

    转载:http://blog.csdn.net/xiadi934/article/details/50786293 项目环境: 在SpringMVC +Spring + MyBatis + MySQL ...

  6. Mybatis的二级缓存、使用Redis做二级缓存

    目录 什么是二级缓存? 1. 开启二级缓存 如何使用二级缓存: userCache和flushCache 2. 使用Redis实现二级缓存 如何使用 3. Redis二级缓存源码分析 什么是二级缓存? ...

  7. mybatis结合redis实战二级缓存(六)

    之前的文章中我们意见分析了一级缓存.二级缓存的相关源码和基本原理,今天我们来分享下了mybatis二级缓存和redis的结合,当然mybatis二级缓存也可以和ehcache.memcache.OSC ...

  8. Springboot Mybatis Redis 实现二级缓存

    前言 什么是mybatis二级缓存? 二级缓存是多个sqlsession共享的,其作用域是mapper的同一个namespace. 即,在不同的sqlsession中,相同的namespace下,相同 ...

  9. SpringBank 开发日志 Mybatis 使用redis 作为二级缓存时,无法通过cacheEnabled=false 将其关闭

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC ...

随机推荐

  1. Web前端学习方向

    第一部分 HTML 第一章 职业规划和前景 职业方向规划定位: web前端开发工程师 web网站架构师 自己创业 转岗管理或其他 web前端开发的前景展望: 未来IT行业企业需求最多的人才 结合最新的 ...

  2. Spring Boot原理

    Spring 钩子之BeanFactoryPostProcessor和BeanPostProcessor的源码学习 https://www.jianshu.com/p/a90a3e617ba6 spr ...

  3. Tomcat远程debug配置

    当我们需要定位生产环境问题,而日志又不清晰的情况下,我们可以借助Tomcat提供的远程调试,设置如下: // Linxu系统: apach/bin/startup.sh开始处中增加如下内容: decl ...

  4. 第04项目:淘淘商城(SpringMVC+Spring+Mybatis)【第十一天】(购物车+订单)

    https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040 ...

  5. centos 7 安装及配置zabbix agent

    一.在被监控主机上设置防火墙,允许zabbix-agent的10050端口通过 二.执行yum list |grep zabbix,找到zabbix的agent安装包并安装 三.在 /etc/zabb ...

  6. trie(字典树)原理及C++代码实现

    字典树,又称前缀树,是用于存储大量字符串或类似数据的数据结构. 它的原理是利用相同前缀来减少查询字符串的时间. 不同于BST把关键字保存在本结点中,TRIE可以想象成把关键字和下一个结点的指针绑定,事 ...

  7. 吴裕雄--天生自然C语言开发: 输入 & 输出

    #include <stdio.h> int main() { ; printf("Number = %d", testInteger); ; } #include & ...

  8. 爱心Java for循环实现

    public class x { public static void main(String[] args) { for (int i = 0, k = 0; i < 14; i++) { i ...

  9. 让Spring不再难懂-mvc篇

    spring mvc简介与运行原理 Spring的模型-视图-控制器(MVC)框架是围绕一个DispatcherServlet来设计的,这个Servlet会把请求分发给各个处理器,并支持可配置的处理器 ...

  10. EXAM-2018-7-29

    EXAM-2018-7-29 未完成 [ ] H [ ] A D 莫名TLE 不在循环里写strlen()就行了 F 相减特判 水题 J 模拟一下就可以发现规律,o(n) K 每个数加一减一不变,用m ...