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

posted on 2019-09-04 22:18  小夏coding  阅读(532)  评论(0编辑  收藏  举报

导航