Redis在web中的应用

 

一般而言redis在java web应用中存在两个主要的场景:

缓存常用的数据

在需要高速读/写的场合使用它快速读写

在 Spring 中使用Redis

  (1)先用 Spring 配置一个 JedisPoolConfig 对象

 

<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!--最大空闲数 -->
        <property name="maxIdle" value="50" />
        <!--最大连接数 -->
        <property name="maxTotal" value="100" />
        <!--最大等待时间 -->
        <property name="maxWaitMillis" value="20000" />
    </bean>

 

  (2)在使用 Spring 提供的RedisTemplate之前需要配置Spring所提供的连接工厂,在 Spring Data Redis 方案中有4种工厂模型:选择其中的一种,JedisConnectionFactory

 

<bean id="connectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="localhost" />
        <property name="port" value="6379" />
        <property name="poolConfig" ref="poolConfig" />
    </bean>

 

  (3)普通的连接使用没有办法把 Java 对象直接存入 Redis,可以使用 Spring 内部提供的 RedisSerializer 接口和一些实现类实现序列化和反序列化。

  JdkSerializationRedisSerializer是使用 JDK 的序列化器进行转换,而StringRedisSerializer使用字符串进行序列化

<bean id="jdkSerializationRedisSerializer"
        class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
        
    <bean id="stringRedisSerializer"
        class="org.springframework.data.redis.serializer.StringRedisSerializer" />

  (4)由于需要配置key和value两个不同的序列化方式,那么可以指定各自使用的序列化器。至此,就可以得到一个Spring提供的RedisTemplate来进行操作Redis

 

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="keySerializer" ref="stringRedisSerializer" />
        <property name="valueSerializer" ref="jdkSerializationRedisSerializer" />
    </bean>

  (5)创建POJO类,必须实现Serializable接口

 

package com.ssm.chapter17.pojo;
import java.io.Serializable;
public class Role implements Serializable {
    
    private static final long serialVersionUID = 6977402643848374753L;
 
    private long id;
    private String roleName;
    private String note;
  /*****************************getter and setter**************************************/
}

 

  (6)使用RedisTemplate操作Redis

 

 

private static void testSpring() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
        Role role = new Role();
        role.setId(1L);
        role.setRoleName("role_name_1");
        role.setNote("note_1");
        redisTemplate.opsForValue().set("role_1", role);
        Role role1 = (Role) redisTemplate.opsForValue().get("role_1");
        System.out.println(role1.getRoleName());
    }

 

  然而,这样的方式可能存在问题:执行set和get方法的Redis连接对象可能来自同一个Redis连接池的不同Redis的连接。为了使得set和get操作都来自同一个连接,可以使用SessionCallback

  (7)使用SessionCallback来将多个命令放入到同一个 Redis 连接中执行

  这里使用匿名类的方式,还可以使用 Lambda 的方式进行编写SessionCallback的业务逻辑。

  由于前后使用的都是同一个连接,因此对于资源损耗就比较小,在使用Redis操作多个命令或者使用事务的时候也会用到它。

 

  

private static void testSessionCallback() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
        Role role = new Role();
        role.setId(1);
        role.setRoleName("role_name_1");
        role.setNote("role_note_1");
        SessionCallback callBack = new SessionCallback<Role>() {
            @Override
            public Role execute(RedisOperations ops) throws DataAccessException {
                ops.boundValueOps("role_1").set(role);
                return (Role) ops.boundValueOps("role_1").get();
            }
        };
        Role savedRole = (Role) redisTemplate.execute(callBack);
        System.out.println(savedRole.getId());
    }
 
  例如,简化成Lambda表达式为:
 
    private static void testSessionCallback() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
        Role role = new Role();
        role.setId(1);
        role.setRoleName("role_name_1");
        role.setNote("role_note_1");
        Role savedRole = (Role) redisTemplate.execute((RedisOperations ops) -> {
            ops.boundValueOps("role_4").set(role);
            return (Role) ops.boundValueOps("role_4").get();
        });
    
        System.out.println(savedRole.getId());
    }
 
}