zoukankan      html  css  js  c++  java
  • java操作redis学习笔记

    一、jedis操作:

    1、POM依赖:

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

    2、建一个连接redis数据库的工具类:

     1 public class RedisUtil {
     2 
     3   //服务器IP地址
     4     private static String ADDR = "x.x.x.x";
     5   
     6   //端口
     7     private static int PORT = 6379;
     8   //密码
     9     private static String AUTH = "123456";
    10   //连接实例的最大连接数
    11     private static int MAX_ACTIVE = 1024;
    12   
    13   //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
    14     private static int MAX_IDLE = 200;
    15   
    16     //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException
    17     private static int MAX_WAIT = 10000;
    18     
    19   //连接超时的时间  
    20     private static int TIMEOUT = 10000;
    21 
    22   // 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
    23     private static boolean TEST_ON_BORROW = true;
    24 
    25     private static JedisPool jedisPool = null;
    26 
    27     /**
    28      * 初始化Redis连接池
    29      */
    30 
    31     static {
    32 
    33         try {
    34 
    35             JedisPoolConfig config = new JedisPoolConfig();
    36             config.setMaxTotal(MAX_ACTIVE);
    37             config.setMaxIdle(MAX_IDLE);
    38             config.setMaxWaitMillis(MAX_WAIT);
    39             config.setTestOnBorrow(TEST_ON_BORROW);
    40             jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
    41 
    42         } catch (Exception e) {
    43 
    44             e.printStackTrace();
    45         }
    46 
    47     }
    48 
    49     /**
    50      * 获取Jedis实例
    51      */
    52 
    53     public synchronized static Jedis getJedis() {
    54 
    55         try {
    56 
    57             if (jedisPool != null) {
    58                 Jedis resource = jedisPool.getResource();
    59                 return resource;
    60             } else {
    61                 return null;
    62             }
    63 
    64         } catch (Exception e) {
    65             e.printStackTrace();
    66             return null;
    67         }
    68 
    69     }
    70 
    71     /***
    72      * 
    73      * 释放资源
    74      */
    75     
    76     public static void returnResource(final Jedis jedis) {
    77             if(jedis != null) {
    78                 jedisPool.returnResource(jedis);
    79             }
    80         
    81     }    
    82 }

    3、实现redis的增删改查:

      1 public class TestRedis {
      2 
      3     private Jedis jedis;
      4     
      5     /**
      6      * 连接redis服务器
      7      */
      8     public void connectRedis() {
      9         jedis=RedisUtil.getJedis();
     10     }
     11     
     12     /**
     13      * redis操作字符串
     14      */
     15     public void testString() {
     16         //添加数据
     17         jedis.set("name", "youcong");
     18         System.out.println(jedis.get("name"));
     19         
     20         //拼接字符串
     21         jedis.append("name", ".com");
     22         System.out.println(jedis.get("name"));
     23         
     24         //删除数据
     25         jedis.del("name");
     26         System.out.println(jedis.get("name"));
     27         
     28         //设置多个键值对
     29         jedis.mset("name","yc","age","22","qq","1933108196");
     30         jedis.incr("age");//加1操作
     31         System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" +jedis.get("qq"));
     32     }
     33     
     34     
     35     /**
     36      * redis操作map集合
     37      */
     38     public void testMap() {
     39         //添加数据
     40         Map<String,String> map = new HashMap<String,String>();
     41         
     42         map.put("name", "yc");
     43         map.put("age", "22");
     44         map.put("qq", "1933108196");
     45         jedis.hmset("user", map);
     46         
     47         //取出users中的Name,执行结果:[minxr]-->注意结果是一个泛型的List
     48         //第一个参数是存入redis中map对象的key,后面跟的是放入map中对象的key,后面的key可以是多个,是可变的
     49         List<String> rsmap = jedis.hmget("user", "name","age","qq");
     50         System.out.println(rsmap);
     51         
     52     
     53         //删除map中的某个键值
     54         jedis.hdel("user", "age");
     55         System.out.println(jedis.hmget("user", "age"));//因为删除了,所以返回的是Null
     56         System.out.println(jedis.hlen("user"));//返回key为user的键中存放的值的个数2
     57         System.out.println(jedis.exists("user"));//是否存在key为user的记录,返回true
     58         System.out.println(jedis.hkeys("user"));//返回map对象中的所有key
     59         System.out.println(jedis.hvals("user"));//返回map对象中的所有value
     60         
     61         Iterator<String> iter = jedis.hkeys("user").iterator();
     62         while(iter.hasNext()) {
     63             String key = iter.next();
     64             System.out.println(key+":" + jedis.hmget("user", key));
     65         }
     66     
     67     }
     68     
     69     /**
     70      * redis操作List集合
     71      */
     72     public void testList() {
     73         //开始前,先移除所有的内容
     74         jedis.del("java framework");
     75         System.out.println(jedis.lrange("java framework", 0, -1));
     76         
     77         //先向key java framework 中存放三条数据
     78         jedis.lpush("java framework","spring");
     79         jedis.lpush("java framework", "struts");
     80         jedis.lpush("java framework", "hibernate");
     81         
     82         //再取出所有数据jedis.lrange是按范围取出
     83         //第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度 -1表示取得所有
     84         System.out.println(jedis.lrange("java framework", 0, -1));
     85         
     86         jedis.del("java framework");
     87         jedis.rpush("java framework", "spring");
     88         jedis.rpush("java framework", "struts");
     89         jedis.rpush("java framework","hibernate");
     90         System.out.println(jedis.lrange("java framework", 0, -1));
     91         
     92         
     93     }
     94     
     95     
     96     /**
     97      * redis操作set集合
     98      * 
     99      */
    100     
    101     public void testSet() {
    102         
    103         //添加
    104         jedis.sadd("user", "liuling");
    105         jedis.sadd("user", "xinxin");
    106         jedis.sadd("user","ling");
    107         jedis.sadd("user", "zhangxinxin");
    108         jedis.sadd("user", "who");
    109         
    110         //删除
    111         jedis.srem("user", "who");
    112         System.out.println(jedis.smembers("user"));//获取所有加入的value
    113         System.out.println(jedis.sismember("user", "who"));//判断who是否是user集合的元素
    114         System.out.println(jedis.srandmember("user"));
    115         System.out.println(jedis.scard("user"));//返回集合的元素个数  
    116     }
    117     
    118     
    119     /**
    120      * redis排序
    121      */
    122     
    123     public void testSort() {
    124         
    125         //jedis 排序
    126         //注意,此处的rpush和lpush是List的操作。是一个双向链表(但从表现来看的)
    127         jedis.del("a");//先清除数据,再加入数据进行测试
    128         jedis.rpush("a", "1");
    129         jedis.lpush("a", "6");
    130         jedis.lpush("a", "3");
    131         jedis.lpush("a", "9");
    132         System.out.println(jedis.lrange("a", 0, -1));
    133         System.out.println(jedis.sort("a"));//[1,3,6,9] //输入排序后结果
    134         System.out.println(jedis.lrange("a", 0, -1));
    135     }
    136     
    137     
    138     /**
    139      * redis连接池
    140      */
    141     
    142     public void testRedisPool() {
    143         
    144         RedisUtil.getJedis().set("newname", "test");
    145         
    146         System.out.println(RedisUtil.getJedis().get("newname"));
    147     }
    148     
    149     public static void main(String[] args) {
    150         TestRedis test = new TestRedis();
    151         test.connectRedis();
    152         test.testSort();
    153     }
    154 }

    二、关于spring-data-redis

    1. 连接池自动管理,提供了一个高度封装的“RedisTemplate”类

    2. 针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口

    ValueOperations:简单K-V操作

    SetOperationsset类型数据操作

    ZSetOperationszset类型数据操作

    HashOperations:针对map类型的数据操作

    ListOperations:针对list类型的数据操作

    3. 提供了对key的“bound(绑定)便捷化操作API,可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key,即BoundKeyOperations

    BoundValueOperations

    BoundSetOperations

    BoundListOperations

    BoundSetOperations

    BoundHashOperations

    4. 将事务操作封装,有容器控制。

    5. 针对数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)

    JdkSerializationRedisSerializerPOJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列。是目前最常用的序列化策略。

    StringRedisSerializerKey或者value为字符串的场景,根据指定的charset对数据的字节序列编码成string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。

    JacksonJsonRedisSerializerjackson-json工具提供了javabeanjson之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。【需要jackson-mapper-asl工具支持】

    OxmSerializer:提供了将javabeanxml之间的转换能力,目前可用的三方支持包括jaxbapache-xmlbeansredis存储的数据将是xml工具。不过使用此策略,编程将会有些难度,而且效率最低;不建议使用。【需要spring-oxm模块的支持】

    三、Spring boot使用RestTemplate

    1、POM依赖:

     1 <dependencies>
     2     <!-- spring boot 配置 -->
     3     <dependency>
     4         <groupId>org.springframework.boot</groupId>
     5         <artifactId>spring-boot-starter-web</artifactId>
     6     </dependency>
     7 
     8     <dependency>
     9         <groupId>org.springframework.boot</groupId>
    10         <artifactId>spring-boot-starter-thymeleaf</artifactId>
    11     </dependency>
    12 
    13     <dependency>
    14         <groupId>org.springframework.boot</groupId>
    15         <artifactId>spring-boot-starter-test</artifactId>
    16         <scope>test</scope>
    17     </dependency>
    18 
    19     <dependency>
    20         <groupId>org.springframework.boot</groupId>
    21         <artifactId>spring-boot-starter-data-redis</artifactId>
    22     </dependency>
    23 </dependencies>

    2、配置文件application.properties:

     1 # Redis数据库索引(默认为0)
     2 spring.redis.database=0  
     3 # Redis服务器地址
     4 spring.redis.host=127.0.0.1
     5 # Redis服务器连接端口
     6 spring.redis.port=6379  
     7 # Redis服务器连接密码(默认为空)
     8 spring.redis.password=
     9 # 连接池最大连接数(使用负值表示没有限制)
    10 spring.redis.pool.max-active=8  
    11 # 连接池最大阻塞等待时间(使用负值表示没有限制)
    12 spring.redis.pool.max-wait=-1  
    13 # 连接池中的最大空闲连接
    14 spring.redis.pool.max-idle=8  
    15 # 连接池中的最小空闲连接
    16 spring.redis.pool.min-idle=0  
    17 # 连接超时时间(毫秒)
    18 spring.redis.timeout=0  

    3、redis操作工具类:

      1 @Component
      2 public class RedisService {
      3     @Autowired
      4     private RedisTemplate<String, String> redisTemplate;
      5 
      6     /**
      7      * 默认过期时长,单位:秒
      8      */
      9     public static final long DEFAULT_EXPIRE = 60 * 60 * 24;
     10 
     11     /**
     12      * 不设置过期时长
     13      */
     14     public static final long NOT_EXPIRE = -1;
     15 
     16 
     17 
     18 
     19     public boolean existsKey(String key) {
     20         return redisTemplate.hasKey(key);
     21     }
     22 
     23     /**
     24      * 重名名key,如果newKey已经存在,则newKey的原值被覆盖
     25      *
     26      * @param oldKey
     27      * @param newKey
     28      */
     29     public void renameKey(String oldKey, String newKey) {
     30         redisTemplate.rename(oldKey, newKey);
     31     }
     32 
     33     /**
     34      * newKey不存在时才重命名
     35      *
     36      * @param oldKey
     37      * @param newKey
     38      * @return 修改成功返回true
     39      */
     40     public boolean renameKeyNotExist(String oldKey, String newKey) {
     41         return redisTemplate.renameIfAbsent(oldKey, newKey);
     42     }
     43 
     44     /**
     45      * 删除key
     46      *
     47      * @param key
     48      */
     49     public void deleteKey(String key) {
     50         redisTemplate.delete(key);
     51     }
     52 
     53     /**
     54      * 删除多个key
     55      *
     56      * @param keys
     57      */
     58     public void deleteKey(String... keys) {
     59         Set<String> kSet = Stream.of(keys).map(k -> k).collect(Collectors.toSet());
     60         redisTemplate.delete(kSet);
     61     }
     62 
     63     /**
     64      * 删除Key的集合
     65      *
     66      * @param keys
     67      */
     68     public void deleteKey(Collection<String> keys) {
     69         Set<String> kSet = keys.stream().map(k -> k).collect(Collectors.toSet());
     70         redisTemplate.delete(kSet);
     71     }
     72 
     73     /**
     74      * 设置key的生命周期
     75      *
     76      * @param key
     77      * @param time
     78      * @param timeUnit
     79      */
     80     public void expireKey(String key, long time, TimeUnit timeUnit) {
     81         redisTemplate.expire(key, time, timeUnit);
     82     }
     83 
     84     /**
     85      * 指定key在指定的日期过期
     86      *
     87      * @param key
     88      * @param date
     89      */
     90     public void expireKeyAt(String key, Date date) {
     91         redisTemplate.expireAt(key, date);
     92     }
     93 
     94     /**
     95      * 查询key的生命周期
     96      *
     97      * @param key
     98      * @param timeUnit
     99      * @return
    100      */
    101     public long getKeyExpire(String key, TimeUnit timeUnit) {
    102         return redisTemplate.getExpire(key, timeUnit);
    103     }
    104 
    105     /**
    106      * 将key设置为永久有效
    107      *
    108      * @param key
    109      */
    110     public void persistKey(String key) {
    111         redisTemplate.persist(key);
    112     }
    113 }

    4、缓存注解的使用:

    (1) @Cacheable:在方法执行前Spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;没有则调用方法并将方法返回值放进缓存。

    (2) @CachePut:将方法的返回值放到缓存中。

    (3) @CacheEvict:删除缓存中的数据。

    注意:

    1)保存到缓存的DTO实体对象要实现Serializable接口,否则会报序列化的错误;

    2)@CachePut注解的cacheNames key 要跟 @Cacheable() 里的一致,才会正确更新,并且和@Cacheable() 注解的方法返回值要一致;

    5、两个redis命令:

    (1) SETNX:将key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做。SETNX是”SET if Not eXists”的简写。

    (2) GETSETGETSET可以和INCR一起使用实现支持重置的计数功能。举个例子:每当有事件发生的时候,一段程序都会调用INCRkey mycounter1,但是有时我们需要获取计数器的值,并且自动将其重置为0。这可以通过GETSET mycounter 0”来实现;

    如:

    redis> INCR mycounter
    (integer) 1
    redis> GETSET mycounter "0"
    "1"
    redis> GET mycounter
    "0"

    6、redis实现的分布式锁:

     1 @Component
     2 @Slf4j
     3 public class RedisLock {
     4 
     5     @Autowired
     6     StringRedisTemplate redisTemplate;
     7 
     8     /**
     9      * 加锁
    10      * @param key
    11      * @param value 当前时间 + 超时时间
    12      * @return
    13      */
    14     public boolean lock(String key, String value){
    15         if (redisTemplate.opsForValue().setIfAbsent(key, value)){
    16             return true;
    17         }
    18 
    19         //解决死锁,且当多个线程同时来时,只会让一个线程拿到锁
    20         String currentValue = redisTemplate.opsForValue().get(key);
    21         //如果过期
    22         if (!StringUtils.isEmpty(currentValue) &&
    23                 Long.parseLong(currentValue) < System.currentTimeMillis()){
    24             //获取上一个锁的时间
    25             String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
    26             if (StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)){
    27                 return true;
    28             }
    29         }
    30 
    31         return false;
    32     }
    33 
    34     /**
    35      * 解锁
    36      * @param key
    37      * @param value
    38      */
    39     public void unlock(String key, String value){
    40 
    41         try {
    42             String currentValue = redisTemplate.opsForValue().get(key);
    43             if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)){
    44                 redisTemplate.opsForValue().getOperations().delete(key);
    45             }
    46         }catch (Exception e){
    47             log.error("【redis锁】解锁失败, {}", e);
    48         }
    49     }
    50 }

    四、参考资料:

    https://www.cnblogs.com/youcong/p/8098881.html

    https://www.cnblogs.com/superfj/p/9232482.html

    https://segmentfault.com/a/1190000017057950

  • 相关阅读:
    字符设备驱动程序
    内存管理
    在React中使用context来传递属性
    iTerm2保存登录密码
    Mac OS设置终端 autocomplete 大小写不敏感
    Linux下安装Google SDK 配置Google API翻译环境
    使用Shell远程给Linux安装JDK
    Linux下wget命令 指定下载文件路径
    linux下解压/压缩命令
    获取鼠标在屏幕上的位置
  • 原文地址:https://www.cnblogs.com/laoxia/p/11461858.html
Copyright © 2011-2022 走看看