Spring Data Redis

Jedis是使用最多的Redis的Java客户端,这种使用方式属于裸用,直接通过Jedis操作Redis特性

主要有:

  • 基本使用
  • 连接池的使用
  • 高可用连接
  • 客户端分片

基本使用

单线程下使用

@Component
public class RedisClientUtil {

    @Value("${spring.redis.host:localhost}")
    private String host;

    @Value("${spring.redis.port:6379}")
    private Integer port;

    private final byte[] tmp_lock = new byte[1];

    private Jedis jedis;

    private RedisClientUtil(){}

    public Jedis getRedisClient(){
        if (jedis == null){
            synchronized (tmp_lock){
                if (jedis == null){
                    jedis = new Jedis(this.host,this.port);
                }
            }
        }
        return jedis;
    }
}

测试代码:

@Autowired
private RedisClientUtil redisClientUtil;

@Test
public void testJedis() {
    Jedis jedis = redisClientUtil.getRedisClient();
    try {
        jedis.set("user1", "admin");
        System.out.println(redisClientUtil.getRedisClient().get("user"));
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        // 注意关闭
        jedis.close();
    }
}

 

连接池的使用

在多线程的环境下,引用连接池的概念帮我们管理各个连接  

@Component
public class RedisClientUtil {

    @Value("${spring.redis.host:localhost}")
    private String host;

    @Value("${spring.redis.port:6379}")
    private Integer port;

    private final byte[] tmp_lock = new byte[1];

    private JedisPool jedisPool;

    private RedisClientUtil(){}

    private JedisPool getRedisClient(){
        if (jedisPool == null){
            synchronized (tmp_lock){
                if (jedisPool == null){
                    jedisPool = new JedisPool(jedisPoolConfig(),this.host,this.port);
                }
            }
        }
        return jedisPool;
    }

    /**
     * 获取Jedis
     * @return
     */
    public Jedis getJedis(){
        return getRedisClient().getResource();
    }

    private JedisPoolConfig jedisPoolConfig(){
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(20);
        jedisPoolConfig.setMaxIdle(10);
        jedisPoolConfig.setMaxWaitMillis(1000);
        return jedisPoolConfig;
    }
}

测试例子:

@Test
public void testJedis() {
    Jedis jedis = redisClientUtil.getJedis();
    try {
        jedis.set("user1", "admin");
        System.out.println(jedis.get("user"));
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        // 注意关闭
        jedis.close();
    }
}

 

高可用连接(master/salve)

Jedis提供哨兵机制的使用

public static void main(String[] args) {

    HashSet<String> hashSet = new HashSet<>();
    hashSet.add("localhost:6379");
    hashSet.add("localhost:6378");
    hashSet.add("localhost:6377");

    JedisSentinelPool pool = new JedisSentinelPool("redis_master_name", hashSet);

    Jedis jedis = pool.getResource();
    try {
        jedis.set("user","user");
        String val = jedis.get("user");
        assert val.equals("user");
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        jedis.close();
    }

}

客户端分片:

public static void main(String[] args) {

    List<JedisShardInfo> shards = new ArrayList<>();
    shards.add(new JedisShardInfo("localhost:6379"));
    shards.add(new JedisShardInfo("localhost:6378"));
    shards.add(new JedisShardInfo("localhost:6377"));

    ShardedJedisPool pool = new ShardedJedisPool(new GenericObjectPoolConfig(),shards);
    ShardedJedis jedis = pool.getResource();
    try {
        jedis.set("user","user");
        String val = jedis.get("user");
        assert val.equals("user");
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        jedis.close();
    }

}

 

Jedis 在实际工作中的正确使用场景

最常见的就是对Service这层的数据加缓存

做法1:

在Service方法中,在得到数据之前,先判断缓存里面有没有通过显示调用JedisUtil类,如果没有就从DB层去获取,再放入Redis中,在更新的时候显示调用JedisUtil去更新缓存,这回出现大量冗余代码

做法2:

自定义一个注解,放在每个方法上,有更新、添加的缓存注解,利用@Aspect拦截机制,调用JedisUtils在拦截器里面处理上下文

 

Spring Data Redis

# reids 服务器地址
spring.redis.host=localhost
# 端口
spring.redis.port=6379
# 连接等待超时时间,毫秒
spring.redis.timeout=6000
# 连接池,最大活跃数
spring.redis.jedis.pool.max-active=8
# 连接池,最大空闲数
spring.redis.jedis.pool.max-idle=8
# 连接池,最大等待时间
spring.redis.jedis.pool.max-wait=-1
# 连接池,最小空闲活动链接数
spring.redis.jedis.pool.min-idle=0

简单实用例子

@Autowired
private static RedisTemplate redisTemplate;

@Test
public void testSDR(){
    redisTemplate.opsForSet().add("user","admin");
}

哨兵高可用配置

# 哨兵的 master 名称
spring.redis.sentinel.master=redis_master
# 哨兵地址
spring.redis.sentinel.nodes=localhost:6379,localhost:6378,localhost:6377

集群分布式切片配置

# 在集群中执行命令时要遵循的最大重定向数
spring.redis.cluster.max-redirects=3
# 集群节点列表
spring.redis.cluster.nodes=localhost:6379,localhost:6378,localhost:6377

调用案例

在实际使用中无论是 RedisTemplate 还是 ValueOperatoration、HashOperation都是可以的

// set 的使用
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Test
public void testSDR(){
    Set<String> sets = this.redisTemplate.opsForSet().members("user1");
    System.out.println(sets);
    if (!sets.isEmpty()){
        sets.forEach(val->this.redisTemplate.opsForSet().remove("user1",val));
    }
    this.redisTemplate.opsForSet().add("user1","admin","user","employee");
}

// Key-val 的使用
@Resource(name = "redisTemplate")
public ValueOperations<String,String> vops;
@Test
public void testVops(){
    String string = vops.get("user");
    System.out.println(string);
    vops.set("user","admin");
}

// hash的使用
@Resource(name = "redisTemplate")
private HashOperations<String,String,Object> hashOps;
@Test
public void testHashOps(){
    // 写入hash
    Map<String,Object> map = new HashMap<>();
    map.put("value","code");
    map.put("key","keyValue");
    hashOps.putAll("myhash",map);
    // 读取hash
    Object value = hashOps.get("myhash","value");
    Object key = hashOps.get("myhash","key");
    System.out.println(value);
    System.out.println(key);
    // 删除hash
    hashOps.delete("myhash","value","key");
}

操作总结

redisTemplate.opsForValue(); // 操作字符串
redisTemplate.opsForHash(); // 操作 hash
redisTemplate.opsForList(); // 操作 list
redisTemplate.opsForSet(); // 操作 set
redisTemplate.opsForZSet(); // 操作 有序set

 

Spring Cache

@Cacheable 注解

应用到读取数据的方法上,如查询方法:先从缓存中读取,如果没有,则调用方法获取数据,然后将数据加入到缓存中

public @interface Cacheable {
    @AliasFor("cacheNames")
    String[] value() default {};
    // cache的名称,根据名称设置不同cache处理类,Redis里面可以根据cache名字设置不同的失效时间
    @AliasFor("value")
    String[] cacheNames() default {};
    // 缓存key的名称,支持spel
    String key() default "";
    // key生成策略,不指定则使用全局默认
    String keyGenerator() default "";
    // 选择不同的CacheManager
    String cacheManager() default "";
    // 配置不同的 cache resolver
    String cacheResolver() default "";
    // 满足什么样的条件才能被缓存,支持spel,可以获取到方法名和方法参数
    String condition() default "";
    // 排除那些返回结果不加入到缓存里面去,支持spel,常见的是 result == null 等
    String unless() default "";
    // 是否同步读取、更新缓存
    boolean sync() default false;
}

@CachePut

调用方法时会自动把响应的数据放入缓存,与@Cacheable不同的是所注解的方法每次都会执行,一般配置到Update和Insert方法上

 

@CacheEvict

public @interface CacheEvict {
    // 与@Cacheable 相同的部分 略....

    // 是否删除所有的实体对象
    boolean allEntries() default false;
    // 是否方法执行之前执行,默认在方法调用成功后删除
    boolean beforeInvocation() default false;
}

@Caching 

所有Cache注解的组合配置方法

public @interface Caching {
    Cacheable[] cacheable() default {};

    CachePut[] put() default {};

    CacheEvict[] evict() default {};
}

@CacheConfig

全局Cache配置

 

@EnableCaching

开启SpringCache默认配置

 

posted @ 2020-11-23 15:56  半雨微凉  阅读(318)  评论(0)    收藏  举报