Redis
Posted xue_yun_xiang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis相关的知识,希望对你有一定的参考价值。
一、SpringBoot与Redis集成
1、引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<!--引入spring mvc 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--
spirng boot 单元测试
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0</version>
</dependency>
<!-- redis 配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
</dependencies>
2、创建配置文件
server.port=8080
# redis 单机配置
spring.redis.host=192.168.12.130
spring.redis.port=6379
#redis 集群配置
#spring.redis.cluster.nodes=192.168.12.130:7001,192.168.12.130:7002,192.168.12.130:7003,192.168.12.130:7004,192.168.12.130:7005,192.168.12.130:7006
#spring.activemq.close-timeout=5000
3、创建启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication
public static void main(String[] args)
SpringApplication.run(MyApplication.class,args);
4、单元测试类
重点:必须和启动类同一包
package com.qfedu;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.*;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
/**
* 当前单元测试类 必须和启动类 在同一包下
*/
@RunWith(SpringRunner.class)
@SpringBootTest // 表明当前类是 springboot 单元测试类 必须和启动类 在同一包下
public class RedisTest
/**
* StringRedisTemplate 所有存储数据都是string 字符串
* Template 模板 模板设计模式
* 作用为使用方式 提供统一的 方法调用
*
*/
@Autowired // 从容器中获取stringRedisTemplate key String value 也是string (hash 除外)
private StringRedisTemplate stringRedisTemplate;
@Test
public void stringTest()
// ValueOperations 就是 springboot 对应 redis 提供的 key String (key value) 类型的的操作类
ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
valueOperations.set("name", "xiaoing ");
String name = valueOperations.get("name");
System.out.println("name = " + name);
@Test
public void hastTest()
// 操作 值为 hash 接口
HashOperations<String, Object, Object> hashOperations = stringRedisTemplate.opsForHash();
// 设置数据
hashOperations.put("user1", "name", "xiaoxue");
String name = (String) hashOperations.get("user1", "name");
System.out.println("name = " + name);
/**
* 测试 list
*/
@Test
public void listTest()
ListOperations<String, String> listOperations = stringRedisTemplate.opsForList();
listOperations.leftPush("list1", "a");
listOperations.leftPush("list1", "b");
listOperations.leftPush("list1", "c");
List<String> list1 = listOperations.range("list1", 0, -1);
System.out.println("list1 = " + list1);
@Test
public void boundValueTest()
// 在获取时 直接绑定了key 省去了每次操作制定 key 的流程
BoundValueOperations<String, String> valueOps = stringRedisTemplate.boundValueOps("name");
valueOps.set("xiaowang");
String name = valueOps.get();
System.out.println("name = " + name);
/**
* 绑定 key value Hash
*/
@Test
public void boundHashTest()
BoundHashOperations<String, Object, Object> hashOps = stringRedisTemplate.boundHashOps("user1");
hashOps.put("name", "xiaocui");
Object name = hashOps.get("name");
System.out.println("name = " + name);
五、在springboot reids启动器中提供了两个模板类
StringRedisTemplate
public class StringRedisTemplate extends RedisTemplate<String, String>
public StringRedisTemplate()
this.setKeySerializer(RedisSerializer.string());
this.setValueSerializer(RedisSerializer.string());
this.setHashKeySerializer(RedisSerializer.string());
this.setHashValueSerializer(RedisSerializer.string());
RedisTemplate
public void afterPropertiesSet()
super.afterPropertiesSet();
boolean defaultUsed = false;
if (this.defaultSerializer == null)
this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
if (this.enableDefaultSerializer)
if (this.keySerializer == null)
this.keySerializer = this.defaultSerializer;
defaultUsed = true;
if (this.valueSerializer == null)
this.valueSerializer = this.defaultSerializer;
defaultUsed = true;
if (this.hashKeySerializer == null)
this.hashKeySerializer = this.defaultSerializer;
defaultUsed = true;
if (this.hashValueSerializer == null)
this.hashValueSerializer = this.defaultSerializer;
defaultUsed = true;
if (this.enableDefaultSerializer && defaultUsed)
Assert.notNull(this.defaultSerializer, "default serializer null and not all serializers initialized");
if (this.scriptExecutor == null)
this.scriptExecutor = new DefaultScriptExecutor(this);
this.initialized = true;
RedisTemplate 与 StringRedisTemplate区别
- RedisTemplate:
RedisTemplate是最基本的操作类,它默认的序列化方式是JdkSerializationRedisSerializer,在存值时,键值会被序列化为字节数组,可读性差,取值时也是一样,如果redis中存的值正常的字符串形式,取值时将返回null
- StringRedisTemplate:
StringRedisTemplate继承于 RedisTemplate<String, String>,默认的序列化方式是StringRedisSerializer,存值取值都是按照字符串的形式
@Autowired// 序列化 jdk 序列化
private RedisTemplate redisTemplate;
@Test
public void redisTemplateTest1()
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set("str1", "hallo world");
System.out.println("str1:"+valueOperations.get("str1"));
解决RedistTemplate乱码
@Configuration
public class RedisConfig
@Bean("redisTemplate")
public RedisTemplate redisTemplate(RedisConnectionFactory factory, Jackson2JsonRedisSerializer redisJsonSerializer)
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
//redis连接工厂
template.setConnectionFactory(factory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//redis.key序列化器
template.setKeySerializer(stringRedisSerializer);
//redis.value序列化器
template.setValueSerializer(redisJsonSerializer);
//redis.hash.key序列化器
template.setHashKeySerializer(stringRedisSerializer);
//redis.hash.value序列化器
template.setHashValueSerializer(redisJsonSerializer);
//调用其他初始化逻辑
template.afterPropertiesSet();
//这里设置redis事务一致
template.setEnableTransactionSupport(true);
return template;
/**
* 配置redis Json序列化器
*
* @return
*/
@Bean
public Jackson2JsonRedisSerializer redisJsonSerializer()
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
return serializer;
二、Mybatis 使用Redis 作为二级缓存
单机 mybatis 开启二级缓存
1、在配置文件开启全局开关
2、在xml 注解 @CacheNamespace// 开启器二级缓存
mybatis 一级二级 缓存共同点:
在查询时 commit 产生缓存,只要发生增删改 清空缓存
mybatis 查询先去二级缓存,二级再去一级 ,一级没有去数据库差
mybatis-spring 应用中,每调用一次dao接口对应的方法,都会产生一个新的sqlSession,不存在一级缓存
1、mybatis 使用redis 作为二级缓存的优点
优点:
1.提交查询效率
2.节约每个应用的jvm 内存空间 便于垃圾回收
2、在配置文件开启mybatis二级缓存
# 开启mybatis 二级缓存
mybatis.configuration.cache-enabled=true
3、创建 自定缓存类
package com.qfedu.cache;
import org.apache.ibatis.cache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 自定义 mybatis 二级缓存 底层使用 redis 存储
*
* 当前 cache 没有加入到容器
*
*/
public class RedisCache implements Cache
private String id;
// 读写锁 可以多个人同时读,只要有一个人写 其他人都不能读
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public RedisCache()
public RedisCache(String id)
System.out.println("命名空间-----id:"+id);
this.id = id;
// 获取的id 就是 当前mapper 的命名空间
public String getId()
return id;
/**
* 向缓存中存放数据 key(类似sql) value (查询结果)
* @param o
* @param o1
*/
public void putObject(Object key, Object value)
System.out.println("存储 key = " + key);
getRedisTemplate().opsForValue().set(key.toString(), value, 10, TimeUnit.MINUTES);
/**
* 获取缓存是 通过 key
* @param key
* @return
*/
public Object getObject(Object key)
System.out.println("获取key 对应的值 key = " + key);
return getRedisTemplate().opsForValue().get(key.toString());
/**
* 清除key 对应的缓存
* @param key
* @return
*/
public Object removeObject(Object key)
System.out.println("删除 key = " + key);
return getRedisTemplate().delete(key.toString());
/**
* 清空当前命名空间二级缓存
* 就是删除所有 对应namespace(id) 的 key
*/
public void clear()
// 获取到所有包含 namespace(id) 的 key
Set<String> keys = getRedisTemplate().keys("*" + id + "*");
for (String key : keys)
System.out.println("遍历清空所有的namespace 下 的key = " + key);
getRedisTemplate().delete(key);
/**
* 获取当前命名空间对应的条数
* @return
*/
public int getSize()
System.out.println("获取当前命名空间下 的条数");
// 获取到所有包含 namespace(id) 的 key
Set<String> keys = getRedisTemplate().keys("*" + id + "*");
return keys.size();
public ReadWriteLock getReadWriteLock()
return readWriteLock;
/**
* 获取容器中的 redisTemplate
* @return
*/
public RedisTemplate getRedisTemplate()
// 获取到容器
ApplicationContext applicationContext = ApplicationHolder.getApplicationContext();
return (RedisTemplate) applicationContext.getBean("redisTemplate");
package com.qfedu.cache;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
*
* ApplicationContextAware 作用 就是 在生成 对应的实例是调用,将容器ApplicationContext 传进来
*/
@Component// 将当前类加入到容器中 ,如果当前类实现ApplicationContextAware 还会在创建bean调用改接口对应的setApplicationContext
public class ApplicationHolder implements ApplicationContextAware
private static ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
// 持有上下文对象
this.applicationContext = applicationContext;
/**
* 获取核心容器
* @return
*/
public static ApplicationContext getApplicationContext()
return applicationContext;
4、在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="com.qfedu.dao.StudentDao">
<!-- 开启二级缓存
type="" mybatis 会使用 用户自定的二级缓存 存储 如果没有配置就是用 jvm
mybatis 创建 RedisCache ,没有加入到容器中
-->
<cache type="com.qfedu.cache.RedisCache" eviction="LRU" size="1024" flushInterval="60"></cache>
<!--
在springboot中使用别名有 警告 误报没有影响
可以使用全限定名解决 com.qfedu.entity.Student
-->
<select id="findAllStudent" resultType="com.qfedu.entity.Student">
select * from student_tb
</select>
<update id="updateStudent">
update student_tb set name = #name,age = #age,sex = #sex,height=#以上是关于Redis的主要内容,如果未能解决你的问题,请参考以下文章