Spring Boot集成Redis
在 NoSQL 数据库这个分类中,Redis 也是非常流行并且极具特色的一款产品。与适合处理海量数据易于扩展的 MongoDB 不同,Redis 在性能方面更为突出。
Redis 作为内存型的键值数据库,以高度优化的存储结构将数据保存至内存,这使得该产品的性能可以在各数据库之中排到第一梯队。也是因为性能如此突出,在大多应用开发中,Redis 往往会被当成缓存使用,用于缓存其他数据库中的热点数据,以提高整个系统的查询性能。
本文将使用 Spring Data Redis 来整合 Redis 数据库,同时也会为开发人员提供模板以及 Repository 这两种通用的数据访问形式。
Spring Data Redis 默认集成了 Lettuce 作为连接客户端。如果要另外使用 Jedis,需要另外引入对应的依赖。
示例代码 StudentRepository.java:
操作 RedisTemplate 的示例代码如下:
声明:《Java系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。
Redis 作为内存型的键值数据库,以高度优化的存储结构将数据保存至内存,这使得该产品的性能可以在各数据库之中排到第一梯队。也是因为性能如此突出,在大多应用开发中,Redis 往往会被当成缓存使用,用于缓存其他数据库中的热点数据,以提高整个系统的查询性能。
本文将使用 Spring Data Redis 来整合 Redis 数据库,同时也会为开发人员提供模板以及 Repository 这两种通用的数据访问形式。
准备工作
为了能够使用到 Spring Data Redis 项目所提供的功能,需要引入对应的 starter 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
另外,连接 Redis 有两种客户端解决方案:
- Lettuce 。
- Jedis。
Spring Data Redis 默认集成了 Lettuce 作为连接客户端。如果要另外使用 Jedis,需要另外引入对应的依赖。
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
在引入依赖之后,需要声明一个配置项用于启用 Repository 以及模板。示例代码如下:
@Bean
public LettuceConnectionFactory redisConnectionFactory(){
//使用Lettuce作为客户端需要声明该Bean
RedisStandaloneConfiguration redisStandaloneConfiguration=new RedisStandaloneConfiguration(hostName,port);
//如果有密码,则需要通过setPassword设置对应密码
redisStandaloneConfiguration.setPassword(password);
return new LettuceConnectionFactory(redisStandaloneConfiguration);
}
@Bean
public JedisConnectionFactory jedisConnectionFactory(){
//使用Jedis作为客户端需要声明该Bean
RedisStandaloneConfiguration redisStandaloneConfiguration=new RedisStandaloneConfiguration(hostName,port);
redisStandaloneConfiguration.setPassword(password);
return new JedisConnectionFactory(redisStmndAloneConfigurmtion);
}
@Bean
public RedisTemplate<?, ?> redisTemplate(){
RedisTemplate<String, Object> template=new RedisTemplate<>();
RedisSerializer<String> stringSerializer=new StringRedisSerializer();
JdkSerializationRedisSerializer jdkSerializationRedisSerializer=new JdkSerializationRedisSerializer();
template.setConnectionFactory(redisConnectionFactory());
template.setKeySerializer(stringSerializer);
template.setHashKeySerializer(stringSerializer);
template.setValueSerializer(jdkSerializationRedisSerializer);
template.setHashValueSerializer(jdkSerializationRedisSerializer);
template.setEnableTransactionSupport(true);
template.afterPropertiesSet();
return template;
}
其中 LettuceConnectionFactory 与 JedisConnectionFactory 根据所选的客户端选择声明对应 ConnectionFactory 即可。
使用RedisRepository访问Redis
RedisRepository 延续了 Spring Data 中通用的 Repository 的设计风格,为操作 Redis 带来了简单易用的方式。示例
实体示例代码:
@Accessors(chain = true)
@Getter
@Setter
@RedisHash(value = "Student", timeToLive = 10)
public class Student implements Serializable {
public enum Gender{
MALE, FEMALE
}
private String id;
@Indexed
private String name;
private Gender gender;
private int grade;
}
- @RedisHash 注解用于声明该实体将被存储于 Redis Hash 中,如果需要使用 Repository 的数据访问形式,这个注解是必须使用到的;
- timeToLive 属性用于标注该实体对象在数据库中的有效期,单位为秒;
- @Indexed 注解用于标注需要作为查询条件的属性。
示例代码 StudentRepository.java:
@Repository
public interface StudentRepository extends CrudRepository<Student, String> {
//自定义查询方式。使用标注了@Indexed的name属性进行查询
Student findByName(String name);
}
调用示例代码如下:
@SpringBootTest
class RedisApplicationTests {
@Autowired
StudentRepository studentRepository;
@Test
void testSave() {
Student student = new Student().setId("20200101007").setName("zbc").setGender(Student.Gender.MALE).setGrade(1);
//根据Id新增或更新记录
studentRepository.save(student);
}
@Test
void testFindBy() {
//使用主键查询
assert studentRepository.findById("20200101007").isPresent();
//根据自定义方法查询
assert studentRepository.findByName("zbc") != null;
}
@Test
void testDelete() {
//根据主键删除
studentRepository.deleteById("20200101007");
assert !studentRepository.findById("20200101007").isPresent();
}
@Test
void testFindAll() {
studentRepository.save(new Student().setId("20200101007").setName("zbc").setGender(Student.Gender.MALE).setGrade(1));
studentRepository.save(new Student().setId("20200101008").setName("cc").setGender(Student.Gender.FEMALE).setGrade(1));
studentRepository.save(new Student().setId("20200101009").setName("gf").setGender(Student.Gender.MALE).setGrade(1));
studentRepository.save(new Student().setId("20200101010").setName("mjyl").setGender(Student.Gender.FEMALE).setGrade(1));
//查询全部记录
List<Student> studentList = Lists.newArrayList(studentRepository.findAll());
assert studentList.size() >0;
}
}
使用RedisTemplate访问Redis
相对于 RedisRepository,RedisTemplate 更为灵活。RedisTemplate 基于 Redis 的原生命令封装了一系列的操作方法。这些方法基于 Redis 数据结构实现,Redis 的基础数据结构有 5 种:1) String
字符串,Redis 中基础的数据结构。2) List
列表,该数据结构底层的存储形式为链表。插入与删除的操作效率非常高。3) Hash
哈希字典,与 Java 中的 HashMap 非常类似。底层结构为数组与链表。4) Set
集合,与 Java 中的 HashSet 类似。内部的键值对是无序且唯一的。5) Zset
有序集合,又称为 SortedSet。它一方面保证键值对唯一,另一方面会维护键值对的权重属性,为键值对进行排序。操作 RedisTemplate 的示例代码如下:
@SpringBootTest
public class RedisTemplateTests {
@Autowired
RedisTemplate<String, Object> redisTemplate;
@Test
void teststring() {
//设置键-值对
redisTemplate.opsForValue().set("num", "123");
//根据name获取值
redisTemplate.opsForValue().get("num");
//设置带有效期的键-值对
redisTemplate.opsForValue().set("fade-num", "321", 10, TimeUnit.SECONDS);
//10秒后结果为Null
redisTemplate.opsForValue().get("fade-num");
}
@Test
void testList() {
//通过leftPush更新列表,也可以选择rightPush方法
redisTemplate.opsForList().leftPush("languages", "java");
redisTemplate.opsForList().leftPush("languages", "python");
redisTemplate.opsForList().leftPush("languages", "c++");
//查询列表长度
assert redisTemplate.opsForList().size("languages") >= 3;
//弹出列表左边的元素,之后结果在数据库中不复存在
assert Objects.equals(redisTemplate.opsForList().leftPop("languages"), "c++");
//弹出列表右边的元素,之后结果在数据库中不复存在
assert Objects.equals(redisTemplate.opsForList().rightPop("languages"), "java");
}
@Test
void testHash() {
//更新hash第一个参数为hash的键,第二个参数为该hash内键-值对的键
redisTemplate.opsForHash () .put ("hash", "red", "小红");
redisTemplate.opsForHash () .put ("hash", "elephant", "小象");
redisTemplate.opsForHash () .put ("hash", "red-elephant","小红象");
//根据hash的键以及hash内键值对的键检索对应信息
assert Objects.equals(redisTemplate.opsForHash().get("hash", "red"),"小红");
//获取hash内所有键-值对的键
Set<Object>hash = redisTemplate.opsForHash().keys("hash");
hash.forEach(System.out::println);
}
@Test
void testSet() {
//新增set
redisTemplate.opsForSet().add("set", "sir", "yes", "sir", "madam");
//随机弹出一个元素
redisTemplate.opsForSet().pop("set");
//获取set中所有卤容
redisTemplate.opsForSet().members("set").forEach(System.out::println);
}
@Test
void testZSet() {
//新增zset内容
redisTemplate.opsForZSet().add("zset", "sir", -1);
redisTemplate.opsForZSet().add("zset", "sir", 9);
redisTemplate.opsForZSet().add("zset", "yes", 3);
redisTemplate.opsForZSet().add("zset", "madam", 10);
//获取该zset中sir的权重
System.out.println(redisTemplate.opsForZSet().score("zset", "sir"));
//根据权重区间遍历zset
redisTemplate.opsForZSet().range("zset",0, 9).forEach(System.out::println);
}
}声明:《Java系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。