Spring-Data-Redis 入门学习
Spring-Data-Redis 入门学习
参考文章:
https://www.jianshu.com/p/4a9c2fec1079
- 导入 redis 相关依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.7.2.RELEASE</version>
</dependency>
- 配置3个 bean ,连接池配置类 连接工厂类 模板类
JedisPoolConfig JedisConnectionFactory RedisTemplate RedisSerializer
- 提供 redis.properties 文件 (可选)
将 redis 的相关参数从 spring 配置文件中挪到 redis.properties 文件中。
spring 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
">
<!-- 配置连接池 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="10"></property>
<property name="maxIdle" value="10"></property>
<property name="minIdle" value="2"></property>
<property name="maxWaitMillis" value="15000"></property>
<property name="minEvictableIdleTimeMillis" value="300000"></property>
<property name="numTestsPerEvictionRun" value="3"></property>
<property name="timeBetweenEvictionRunsMillis" value="60000"></property>
<property name="testOnBorrow" value="true"></property>
<property name="testOnReturn" value="true"></property>
<property name="testWhileIdle" value="true"></property>
</bean>
<!-- 连接工厂 -->
<bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="127.0.0.1"/>
<property name="port" value="6379"/>
<!--<property name="password" value="123456"/>-->
<property name="usePool" value="true"/>
<property name="poolConfig" ref="jedisPoolConfig"/>
</bean>
<!-- 用于数据交互 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnFactory"/>
</bean>
</beans>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<!-- 序列化策略 推荐使用StringRedisSerializer -->
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
</bean>
SDR序列化方式有多种,如:StringRedisSerializer JdkSerializationRedisSerializer Jackson2JsonRedisSerializer OxmSerializer等等
pom 文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mozq.redis</groupId>
<artifactId>spring-redis-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- redis 相关 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.7.2.RELEASE</version>
</dependency>
<!-- 测试相关 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>
hash 结构测试类 存储简单值
package com.mozq.redis;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
import java.util.Map;
import java.util.Set;
//hash结构,即 map 的测试。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-redis.xml")
public class HashTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testSetEntry(){
BoundHashOperations book = redisTemplate.boundHashOps("book");
book.put("b1", "仙逆");
book.put("b2", "凡人修仙传");
}
@Test
public void testGetEntryKeys(){
Set book = redisTemplate.boundHashOps("book").keys();
System.out.println(book);
}
@Test
public void testGetEntryValues(){
List book = redisTemplate.boundHashOps("book").values();
System.out.println(book);
}
@Test
public void testGetEntries(){
Map book = redisTemplate.boundHashOps("book").entries();
System.out.println(book);
}
@Test
public void testGetEntryValueByEntryKey(){
String book1 = (String) redisTemplate.boundHashOps("book").get("b1");
System.out.println(book1);
}
@Test
public void testRemoveEntry(){
Long row = redisTemplate.boundHashOps("book").delete("b1");
System.out.println(row);
}
@Test
public void testRemoveKey(){
redisTemplate.delete("book");
}
}
hash 结构
EntryValue = List<Map>
@Test
public void testSetEntry(){
BoundHashOperations users = redisTemplate.boundHashOps("users");
//用户列表
List<Map> userList = new ArrayList<>();
//创建用户
Map map1 = new HashMap();
map1.put("name", "刘备");
map1.put("age", 22);
Map map2 = new HashMap();
map2.put("name", "刘备2");
map2.put("age", 23);
//添加用户到列表
userList.add(map1);
userList.add(map2);
users.put("userList", userList);
}
@Test
public void testGetEntryValueByEntryKey(){
List<Map> userList = (List<Map>) redisTemplate.boundHashOps("users").get("userList");
System.out.println(userList);//[{name=刘备, age=22}, {name=刘备2, age=23}]
}
String 类型
RedisSerializer<T> 将一个对象序列化字节数组,存入 redis 。将 redis 得到的字节数组反序列化成对象。
public interface RedisSerializer<T> {
byte[] serialize(T t) throws SerializationException;
T deserialize(byte[] bytes) throws SerializationException;
}
@Test
public void addObj(){
User user = new User();
user.setName("刘备");
user.setAge(20);
redisTemplate.boundValueOps("moStr").set(user);
}//java.lang.ClassCastException: com.mozq.domain.User cannot be cast to java.lang.String
@Test
public void addObj(){
User user = new User();
user.setName("刘备");
user.setAge(20);
redisTemplate.boundValueOps(user).set("孙权");
}//java.lang.ClassCastException: com.mozq.domain.User cannot be cast to java.lang.String
@Test
public void testStrCR(){
redisTemplate.boundValueOps("用户名").set("刘备");
String username = (String) redisTemplate.boundValueOps("用户名").get();
System.out.println(username);//刘备
}
@Test
public void testStrD(){
redisTemplate.delete("用户名");
}
127.0.0.1:6379> keys *
1) "\xe7\x94\xa8\xe6\x88\xb7\xe5\x90\x8d" UTF-8 用户名
2) "\xd3\xc3\xbb\xa7\xc3\xfb" GBK 用户名
127.0.0.1:6379> get "\xd3\xc3\xbb\xa7\xc3\xfb" GBK 用户名
"\xe5\x88\x98\xe5\xa4\x87" UTF-8 刘备
127.0.0.1:6379> get "\xe7\x94\xa8\xe6\x88\xb7\xe5\x90\x8d" UTF-8 用户名
"\xe5\x88\x98\xe5\xa4\x87" UTF-8 刘备
/*
可见 redis 命令行打印就是字节数组的16进制形式。中文字符串 + 编码 = 字节数组。客户端发送给 redis 的是字节数组。
*/
@Test
public void x3() throws UnsupportedEncodingException {
byte[] bytesUTF8 = "用户名".getBytes("UTF-8");
System.out.println(bytesToHexString(bytesUTF8));//e794a8e688b7e5908d
byte[] bytesGBK = "用户名".getBytes("GBK");
System.out.println(bytesToHexString(bytesGBK));//d3c3bba7c3fb
byte[] bytes= "刘备".getBytes("UTF-8");
System.out.println(bytesToHexString(bytes));//e58898e5a487
}
常用字节转换(字符串转16进制,16进制转字符串)https://blog.csdn.net/yyz_1987/article/details/80634224
package org.springframework.data.redis.serializer;
public class StringRedisSerializer implements RedisSerializer<String> {
private final Charset charset;
public StringRedisSerializer() {
this(Charset.forName("UTF8"));
}
public StringRedisSerializer(Charset charset) {
Assert.notNull(charset);
this.charset = charset;
}
public String deserialize(byte[] bytes) {
return (bytes == null ? null : new String(bytes, charset));
}
public byte[] serialize(String string) {
return (string == null ? null : string.getBytes(charset));
}
}
redisTemplate 键值的序列化策略
<!-- 配置RedisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<!-- 序列化策略 推荐使用StringRedisSerializer ,可以通过构造参数指定字符集,默认为 UTF-8 -->
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer">
<constructor-arg ref="gbkCharSet" />
</bean>
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
</bean>
package com.mozq.charset;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.nio.charset.Charset;
//@Component
@Configuration
public class CharSetUtil {
@Bean("gbkCharSet")
public Charset gbkCharSet(){
return Charset.forName("GBK");
}
}
通用操作
// redisTemplate 删除全部的键
@Test
public void deleteAll(){
Set keys = redisTemplate.keys("*");
redisTemplate.delete(keys);
System.out.println(keys);
System.out.println(keys.size());
}
// redis 删除全部键 Redis Flushall 命令用于清空整个 Redis 服务器的数据 ( 删除所有数据库的所有 key )。
127.0.0.1:6379> flushall
OK
实战 hash 的 EntryValue 的值为 List<Map>
hash 结构 EntryValue = List<Map>
存入
@Service
public class TypeTemplateServiceImpl implements TypeTemplateService {
@Autowired
private TbTypeTemplateMapper typeTemplateMapper;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private TbSpecificationOptionMapper specificationOptionMapper;
private void saveToRedis(){
List<TbTypeTemplate> typeTemplateList = typeTemplateMapper.selectByExample(null);
for (TbTypeTemplate typeTemplate : typeTemplateList) {
//缓存品牌列表
List<Map> brandList = JSON.parseArray(typeTemplate.getBrandIds(), Map.class);
redisTemplate.boundHashOps("searchBrandList").put(typeTemplate.getId(), brandList);
//缓存规格列表
List<Map> specList = findSpecList(typeTemplate.getId());
redisTemplate.boundHashOps("searchSpecList").put(typeTemplate.getId(), specList);
}
System.out.println("缓存品牌和规格列表");
}
}
取出
private Map searchBrandAndSpecList(String categoryName){
HashMap map = new HashMap();
Long typeId = (Long) redisTemplate.boundHashOps("searchCategoryList").get(categoryName);
if(typeId != null){
//品牌列表
List<Map> brandList = (List<Map>) redisTemplate.boundHashOps("searchBrandList").get(typeId);
//规格列表
List<Map> specList = (List<Map>) redisTemplate.boundHashOps("searchSpecList").get(typeId);
map.put("brandList", brandList);
map.put("specList", specList);
}
return map;
}
问题 插入 redis 的键,不是程序中设置的键。
redisTemplate模板类在操作 redis 会使用默认的 jdk 方式序列化。我们要手动配置序列化方式为:StringRedisSerializer
127.0.0.1:6379> keys *
1) "categoryList"
2) "heima01"
3) "hema01"
4) "\xac\xed\x00\x05t\x00\bhashkey1"
5) "user"
127.0.0.1:6379> keys *
1) "categoryList"
2) "heima01"
3) "hema01"
4) "book" // 已经好了
5) "\xac\xed\x00\x05t\x00\bhashkey1"
6) "user"
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<!-- 序列化策略 推荐使用StringRedisSerializer -->
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
</bean>
# 如果存储的 value 是对象,则必须实现序列化。
org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.io.NotSerializableException: com.mozq.domain.User
nested exception is redis.clients.jedis.exceptions.JedisDataException: WRONGTYPE Operation against a key holding the wrong kind of value
原因:
造成这个问题,肯定是程序在多处使用了同一个 key ,并且是以不同的类型,有的以 key-value 类型,有的以 key-map ,有的以 key-object 。我这里 categoryList 被多次使用分别以不同的数据结构存储,报错。
# 因为验证失败,获取不到 redis 连接
redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool
Caused by: java.util.NoSuchElementException: Unable to validate object
java.lang.IllegalArgumentException: non null hash key required
原因:
代码逻辑错误,导致 categoryName 变量的值为 null 。报错。
redisTemplate.boundHashOps("searchCategoryList").get(categoryName);
/*
searchMap.get("category") 的值为 null 时,会进入 if ,而实际的逻辑应该进入 else
*/
if(!"".equals(searchMap.get("category"))){
//搜索条件有分类,直接使用这个分类查品牌和规格
resultMap.putAll(searchBrandAndSpecList((String) searchMap.get("category")));
}else{
if(categoryList.size() > 0){
resultMap.putAll(searchBrandAndSpecList(categoryList.get(0)));
}
}
Spring-Data-Redis 入门学习的更多相关文章
- Spring Data Redis入门示例:字符串操作(六)
Spring Data Redis对字符串的操作,封装在了ValueOperations和BoundValueOperations中,在集成好了SPD之后,在需要的地方引入: // 注入模板操作实例 ...
- Spring Data Redis入门示例:Hash操作(七)
将对象存为Redis中的hash类型,可以有两种方式,将每个对象实例作为一个hash进行存储,则实例的每个属性作为hash的field:同种类型的对象实例存储为一个hash,每个实例分配一个field ...
- Spring Data Redis入门示例:数据序列化 (四)
概述 RedisTemplate默认使用的是基于JDK的序列化器,所以存储在Redis的数据如果不经过相应的反序列化,看到的结果是这个样子的: 可以看到,出现了乱码,在程序层面上,不会影响程序的运行, ...
- Spring Data Redis入门示例:基于Jedis及底层API (二)
使用底层API:RedisConnectionFactory和RedisConnection可以直接操作Redis,下面是一个简单的例子: ### Maven依赖 <properties> ...
- spring data jpa入门学习
本文主要介绍下spring data jpa,主要聊聊为何要使用它进行开发以及它的基本使用.本文主要是入门介绍,并在最后会留下完整的demo供读者进行下载,从而了解并且开始使用spring data ...
- Spring Data Jpa 入门学习
本文主要讲解 springData Jpa 入门相关知识, 了解JPA规范与Jpa的实现,搭建springboot+dpringdata jpa环境实现基础增删改操作,适合新手学习,老鸟绕道~ 1. ...
- Spring Data Redis入门示例:程序配置(五)
单机配置 redis.properties配置 #redis的服务器地址 redis.host=127.0.0.1 #redis的服务端口 redis.port=6379 #客户端超时时间单位是毫秒 ...
- Spring Data Redis入门示例:基于RedisTemplate (三)
使用底层API:RedisConnection操作Redis,需要对数据进行手动转换(String <---->byte),需要进行多数重复性工作,效率低下:org.springframe ...
- Spring Data Redis —— 快速入门
环境要求:Redis 2.6及以上,javase 8.0及以上: 一.Spring Data Redis 介绍 Spring-data-redis是spring的一部分,提供了在srping应用中通过 ...
- Spring Data Redis学习
本文是从为知笔记上复制过来的,懒得调整格式了,为知笔记版本是带格式的,内容也比这里全.点这里 为知笔记版本 Spring Data Redis 学习 Version 1.8.4.Release 前言 ...
随机推荐
- 搭建 Web 网站常用技能
为软件创建专用数据库及其账号 create database if not exists gitea default charset = utf8mb4; grant ALL PRIVILEGES o ...
- java 声明并初始化字符串变量
public class Sample { public static void main(String[] args) { String str = "Hello world"; ...
- oracle--oracle18C DBCA建库(一)
一,环境配置 克隆或者安装一台oracle18c 只需要安装软件即可 主机名 ip 角色 db_inique oracle18c 192.168.0.162 主 oracle oracle18c2 1 ...
- [转载]3.15 UiPath图片操作保存图片的介绍和使用
一.保存图像 (Save Image)的介绍 可以将图像保存到磁盘的一种活动 二.保存图像 (Save Image)在UiPath中的使用 1.打开设计器,在设计库中新建一个Sequence,为序列命 ...
- Git的学习总结
首先,Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. Git 也是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件. ...
- 原创|强大!Nginx 配置在线一键生成“神器”
Nginx作为一个轻量级的HTTP服务器,相比Apache优势也是比较明显的,在性能上它占用资源少,能支持更高更多的并发连接,从而达到提高访问效率;在功能上它是一款非常优秀的代理服务器与负载均衡服务器 ...
- Java判断Integer类型的值是否相等
我们知道Integer是int的包装类,在jdk1.5以上,可以实现自动装箱拆箱,就是jdk里面会自动帮我们转换,不需要我们手动去强转,所以我们经常在这两种类型中随意写,平时也没什么注意 但Integ ...
- 外网IP和内网IP区别
外网IP和内网IP区别? 网络结构 如图,假设我们的计算机现在就是设备一,我们想要访问百度.如果我们正使用着校园网,那么首先我们需要先通过校园网的路由器把我们的内网ip转为校园网的外网ip.然后通过这 ...
- ASP.NET Core中使用MialKit实现邮件发送
# 导包 首先我们需要导入 MailKit NuGet包,NuGet安装包命令在下方拓展介绍中. # 引用命名空间 using MailKit.Net.Smtp; using MimeKit; # 邮 ...
- Linux之《荒岛余生》(三)内存篇
原文:https://juejin.im/post/5c00aee06fb9a049be5d3641 小公司请求量小,但喜欢滥用内存,开一堆线程,大把大把往jvm塞对象,最终问题是内存溢出. 大公司并 ...