Spring-Data-Redis learning portal

Spring-Data-Redis learning portal

Reference article:

https://www.jianshu.com/p/4a9c2fec1079

  1. Import redis its dependencies
<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>
  1. Configuration 3 bean, connection pool configuration template class factory class type connector

JedisPoolConfig JedisConnectionFactory RedisTemplate RedisSerializer

  1. Provide redis.properties file (optional)

The relevant parameters redis moved redis.properties file from the spring configuration file.

spring configuration

<?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 file

<?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>

simple hash value stored in the class structure of the test

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 structure

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 type

RedisSerializer<T>A byte array object serialization, stored redis. The byte array redis obtained deserialized into objects.

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
}

Common-byte converter (hexadecimal string rotation, string of 16 hexadecimal rotation) 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 key serialization strategy

<!-- 配置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");
    }

}

Spoken operation

// 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
The actual hash value EntryValue List<Map>

hash 结构 EntryValue = List<Map>

Deposit
@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("缓存品牌和规格列表");
    }
}
take out
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 insert key issues, the key is not set in the program.

redisTemplate template class in redis uses the default operating mode jdk serialization. We have to manually configure serialization is: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)));
    }
}

Guess you like

Origin www.cnblogs.com/mozq/p/11306835.html