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笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。