jedis

  • jdeis是redis官方推出的连接redis的客户端,貌似自带了redis驱动

    导入依赖

    1. <dependency>
    2. <groupId>redis.clients</groupId>
    3. <artifactId>jedis</artifactId>
    4. <version>3.7.0</version>
    5. </dependency>

    建立连接并使用

  • redis操作极其简单,建立一个连接对象,连接对象便可以通过各种方法直接操作

    • redis不像mysql一样可以有多个用户,多个连接。一个redis服务就一个用户,即一个连接。所以配置下url和密码即可
  • 通过java操作redis插入的中文是可以正确显示和插入中文的,而在redis-cli中不配置插入的中文是乱码或者是\x??形式的编码
  • redis方法用法跟命令几乎一模一样的用法 ```java Jedis jedis = new Jedis(“localhost”,[Integer port]); //连接本地的 Redis 服务 port不传就cao’y jedis.auth(“password”); //如果设置了密码则配置密码 System.out.println(“服务状态: “+jedis.ping()); //正常返回为:PONG

//字符串 jedis.set(“name”,”饶泽东”); jedis.get(“name”);

//删除键值对 jedis.del(“name”);

//哈希 hmset(String , Map) hget(“键”,”属性”)

//list lpush(“键”,String …); //…即是可变参数列表 List lrange(String, long, long);

//set sadd(“键”,String …) Set smembers(“键”)

//zset zadd(“键”, double, “值”)

jedis.close();

  1. <a name="oakho"></a>
  2. ### 事务
  3. ```java
  4. Transaction multi=jedis.multi(); //开启事务
  5. try{
  6. multi.set("name","rzd"); //一系列入队命令...
  7. multi.exec(); 执行事务
  8. } catch(Exception e){
  9. multi.discard();
  10. } finally{
  11. jedis.close();
  12. }

spring-data-redis

  • springboot1.xspring-data-redis的底层实现 是jedis,2.x换为了lettuce

    RedisTemplate

  • RedisTemplate是Spring框架对Jedis API的进行了高度封装,支持连接池自动管理,我们可以在Spring应用中通过简单的连接池配置信息就能访问Redis服务并进行相关缓存操作

    • 默认提供了两个使用Redis的类StringRedisTemplateRedisTemplate
      • RedisTemplate可以支持Redis没有的缓存对象的操作
      • StringRedisTemplate用来存储字符串
  • jedis每次使用都会创建一个连接,不节省资源。同时jedis是单线程操作的,多线程使用有隐患

    • jedis自己其实也提供了一个连接池jedisPool

      Lettuce

  • Lettuce:一个基于Netty的高性能Redis客户端。lettuce依赖于commons-pools

    • commons-pools是一个对象池框架/组件

      源码

  • @ConditionalOnClass表明redisTemplate是可以自定义的

  • 默认绑定的配置文件名为RedisProperties
  • RedisProperties是个实体配置类,开头有@ConfigurationProperties(prefix="spring.redis")表明会寻找配置文件里spring.redis.?的配置进行注入

image.png

springboot中使用redis

Lettuce的Timed out问题

  • 在 Spring Boot 2.x 默认使用 Lettuce 之后,会偶发性出现 Redis command timed out 问题,从而导致客户端(Java 代码)无法连接到 Redis Server 的问题。
  • 这种问题无法正面解决,只能放弃使用Lettucespringboot2.x情况下需要手动排除 spring-data-redis 对 Lettuce 的依赖,并引入 Jedis 依赖

    配置

    ```yaml spring.redis.host=127.0.0.1 spring.redis.port=6379 #使用默认端口时无需配置 spring.redis.database=0 #指定使用的分区片,使用默认片时无需配置 spring.redus.password=

整合了lettuce的详细配置

spring: redis: host: localhost

  1. # 连接超时时间(记得添加单位,Duration)
  2. timeout: 10000ms
  3. # Redis默认情况下有16个分片,这里配置具体使用的分片
  4. # database: 0
  5. lettuce:
  6. pool:
  7. # 连接池最大连接数(使用负值表示没有限制) 默认 8
  8. max-active: 8
  9. # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
  10. max-wait: -1ms
  11. # 连接池中的最大空闲连接 默认 8
  12. max-idle: 8
  13. # 连接池中的最小空闲连接 默认 0
  14. min-idle: 0

cache:

  1. # 一般来说是不用配置的,Spring Cache 会根据依赖的包自行装配
  2. type: redis #配置缓存的实现
  1. <a name="BKdKo"></a>
  2. ## 引入依赖
  3. ```java
  4. <dependency>
  5. <groupId>org.springframework.boot</groupId>
  6. <artifactId>spring-boot-starter-data-redis</artifactId>
  7. </dependency>
  8. <!-- 对象池,使用redis时必须引入,lettuce使用commons-pool2创建redis连接池 -->
  9. <dependency>
  10. <groupId>org.apache.commons</groupId>
  11. <artifactId>commons-pool2</artifactId>
  12. </dependency>
  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-data-redis</artifactId>
  4. <exclusions> <!-- 从依赖关系中排除 -->
  5. <exclusion>
  6. <groupId>io.lettuce</groupId>
  7. <artifactId>lettuce-core</artifactId>
  8. </exclusion>
  9. </exclusions>
  10. </dependency>
  11. <dependency>
  12. <groupId>redis.clients</groupId>
  13. <artifactId>jedis</artifactId>
  14. </dependency>

使用Template与配置bean

  • 其实StringRedisTemplate也是继承自RedisTemplate,所以RedisTemplate也可以 操作字符串
  • 更多见链接

重写RedisTemplate

  • 在RedisAutoConfigiration中RedisTemplate<T,T>2个泛型均为Object类型,Object最后还是尝试序列化为String写入。而我们需要实现redis自动序列化和反序列化,这样更加方便
    • 第一个T代表键值,我们重写时应该为String,否则直接传字符串对象会出现键值除了字符串值还有对象信息
    • 第二个T设置为Serializable/Object,通过jackson等工具序列化可以避免乱码,默认的jdk序列化的结果还是特殊编码字符串
  • 实体类必须实现序列化接口,同时引入一个序列化工具,推荐jackson。

    1. public class User implements Serializable{...}
    1. @Configuration
    2. @AutoConfigureAfter(RedisAutoConfiguration.class)
    3. @EnableCaching
    4. public class RedisConfig {
    5. @Bean
    6. public RedisTemplate<String, Object> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
    7. RedisTemplate<String, Object> template = new RedisTemplate<>();
    8. //配置键的序列化方式,传一个RedisSerializer的实现类对象即可,下面也可以2个都传jackson,stringredisserializer不清楚是哪种序列方式
    9. template.setKeySerializer(new StringRedisSerializer());
    10. //配置值的序列方式
    11. template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    12. //配置连接方式 这里跟上面一样,传个连接接口实现类对象,这里我们传lettuce连接池对象
    13. template.setConnectionFactory(redisConnectionFactory);
    14. return template;
    15. }
    16. }

    redisTemplate使用

  • 不存在的key获取为null

image.png

  1. @Autowired
  2. private StringRedisTemplate stringRedisTemplate; //字符串存储
  3. @Autowired
  4. private RedisTemplate<String, Object> redisCacheTemplate; //对象操作
  5. //----------------操作基本类与集合类-----------
  6. stringRedisTemplate.opsForValue().set("k1", "v1"); //字符串操作
  7. String k1 = stringRedisTemplate.opsForValue().get("k1");
  8. redisCacheTemplate.opsForValue().set(键名, T); //Map操作
  9. T t=(T) redisCacheTemplate.opsForValue().get(键名);
  10. redisTemplate.opsForList().leftPushAll("list", "rzd");
  11. redisTemplate.opsForList().leftPushAll("list", "lhy");
  12. List<Object> S= listOps.range("listcollection4",0,-1);
  13. 对于list等多元素集合,直接传入序列化集合对象不会对每个元素依次插入,
  14. 而是插入一个包含所有元素的字符串。暂时不清楚怎么把一个多元素集合插入为正确的格式
  15. //-----------------设置时效-----------------------
  16. opsForValue().getOperations().getExpire(键); 获取剩余时间,-2为不存在或者已过期(已过期即一般不存在被清空),-1为存在但是未设置过期时间
  17. //-----------------删除key------------
  18. redisTemplate.delete("key)
  1. RedisConnection conn=redisTemplate.getConnectionFactory.getConnection();
  2. //连接较为少用,一般用于操作redis数据库,如
  3. conn.flushDb();
  4. conn.flushAll();

注解使用缓存

  • 借助spring cache实现对缓存操作。核心注解为 @Cacheable@CachePut@CacheEvict 这几个注解根据入参与返回值以实现缓存与方法内部数据的一致性,使用方法的同时也会自动操作缓存
  • 估计是配置类决定的spring cache的缓存实现技术

    配置类

  • 在redisTemplate的配置类中追加如下配置bean

    1. @Bean
    2. public CacheManager cacheManager(RedisConnectionFactory factory) {
    3. // 配置序列化
    4. RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
    5. RedisCacheConfiguration redisCacheConfiguration = config.serializeKeysWith(RedisSerializationContext
    6. .SerializationPair.fromSerializer(new StringRedisSerializer())).
    7. serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
    8. return RedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration).build();
    9. }

    使用

  • 有三个操作注解,value参数为命名空间,key为键名。注解就相当于一个操作方法。下面注解都支持spEl表达式。具体使用参考springboot教程电子书

    • @CacheEvict删除
    • @Cacheable查询 如果缓存存在这个key,则不执行方法直接走缓存。否则走方法,并在方法返回时将结果也存入缓存。
    • @CachePut增加/更新 不管是否存在这个key,都会执行方法,有时使用该注解仅仅是表明该方法支持缓存 cacheput和cacheable的注解参数是相同的
  • 官方强烈不推荐将 @Cacheable 和 @CachePut 注解到同一个方法。
  • 注解方式会生成一个命名空间,里面存不同的东西。只有一个元素时就显示为命名空间::键

image.png image.png

  1. 这里表示键名为user
  2. @CachePut(value = "user", key = "#user.id")
  3. public void saveOrUpdate(User user) { }
  4. @Cacheable(value = "user", key = "#id") //对应多个键时使用数组:{"a","b"},还可以设置条件,条件为true时才会进行缓存
  5. public User get(Long id) { new User(); }
  6. @CacheEvict(value = "user", key = "#id")
  7. public void get(Long id) {}

redis实现session共享

  • 集群环境下session共享本质还是一个缓存环境对应多个服务,只不过多了几个备用的redis机子
  • 首先需要导入依赖,这个依赖的作用是添加分布式session共享的支持,暂时还不是很清楚

    依赖

    1. <dependency>
    2. <groupId>org.springframework.session</groupId>
    3. <artifactId>spring-session-data-redis</artifactId>
    4. </dependency

    配置类

    1. @Configuration
    2. @EnableRedisHttpSession
    3. //可以配置session的失效时间@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 60)
    4. public class RedisSessionConfig{
    5. //...
    6. }
  • 使用注解@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 60) /

    整合布隆过滤器

  • 首先导入google提供的guava,里面有个布隆

  • 链接 可以使用redis官方的布隆实现,能对字符串也进行存读

    1. @Bean
    2. public BloomFilter initBloomFilter() {
    3. BloomFilter<Integer> filter = BloomFilter.create(Funnels.integerFunnel(), 1500, 0.01);
    4. return filter;
    5. }

    *Redis Repositories

  • Spring Data Redis 从 1.7 开始提供 Redis Repositories功能 ,可以无缝的转换并存储实体类。使用哈希类型存储实体类

    • 即一个实体类对应一个redis中的键值对,该键值对可以存储很多该类对象
    • spring Data RedisRepository的基本实现为:CrudRepository
  • 个人猜测spring cache存储于redis中的结果和这个Repositories是一样的,都是?:数字的形式
  • 感觉不是很实用,每种类都要实现一个接口,不如直接使用自动序列化存入redis里面

    启用Repositories

  • 使用@EnableRedisRepositories(basePackages = "...")

    • basePackage参数默认为扫描入口类平级与之下的所有类,查看哪些类头上@Repository
      • 如果是同时使用 spring-data-jpaspring-data-redis 时,由于它们的 Repository的祖先中都有 CrudRepository因此会造成冲突。虽有,最好还是加上 basePackages属性并为它赋值,指定各自扫描的路径,以避免冲突

        实体类添加相应注解

  • @RedisHash表示将 User 类的对象都对应 Redis 中的键名为 user的 Set,每个Set里可以存储多个该实体类对象。此时每个对象的key为user:<Id>,如user:1

    • 获取该redis键值对中某个对象的属性hget user:1 username
  • @Id:标注于实体类的唯一标识字段上

    1. @RedisHash("user")
    2. public class User implements Serializable {
    3. private static final long serialVersionUID = 1L;
    4. @Id
    5. private Long id;
    6. private String userName;
    7. private String password;
    8. private String email;
    9. }

    创建Repository接口

    1. @Repository
    2. public interface UserRepository extends CrudRepository<User, Long> {
    3. }