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());
}
}