一、jedis****操作:
1、POM依赖:
11 <dependency> 22 <groupId>redis.clients</groupId> 33 <artifactId>jedis</artifactId> 44 <version>2.5.0</version> 55 </dependency>
2、建一个连接redis数据库的工具类:
1 1 public class RedisUtil { 2 2 3 3 //服务器IP地址 4 4 private static String ADDR = "x.x.x.x"; 5 5 6 6 //端口 7 7 private static int PORT = 6379; 8 8 //密码 9 9 private static String AUTH = "123456"; 1010 //连接实例的最大连接数 1111 private static int MAX_ACTIVE = 1024; 1212 1313 //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。 1414 private static int MAX_IDLE = 200; 1515 1616 //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException 1717 private static int MAX_WAIT = 10000; 1818 1919 //连接超时的时间 2020 private static int TIMEOUT = 10000; 2121 2222 // 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的; 2323 private static boolean TEST_ON_BORROW = true; 2424 2525 private static JedisPool jedisPool = null; 2626 2727 /** 2828 * 初始化Redis连接池 2929 */ 3030 3131 static { 3232 3333 try { 3434 3535 JedisPoolConfig config = new JedisPoolConfig(); 3636 config.setMaxTotal(MAX_ACTIVE); 3737 config.setMaxIdle(MAX_IDLE); 3838 config.setMaxWaitMillis(MAX_WAIT); 3939 config.setTestOnBorrow(TEST_ON_BORROW); 4040 jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH); 4141 4242 } catch (Exception e) { 4343 4444 e.printStackTrace(); 4545 } 4646 4747 } 4848 4949 /** 5050 * 获取Jedis实例 5151 */ 5252 5353 public synchronized static Jedis getJedis() { 5454 5555 try { 5656 5757 if (jedisPool != null) { 5858 Jedis resource = jedisPool.getResource(); 5959 return resource; 6060 } else { 6161 return null; 6262 } 6363 6464 } catch (Exception e) { 6565 e.printStackTrace(); 6666 return null; 6767 } 6868 6969 } 7070 7171 /*** 7272 * 7373 * 释放资源 7474 */ 7575 7676 public static void returnResource(final Jedis jedis) { 7777 if(jedis != null) { 7878 jedisPool.returnResource(jedis); 7979 } 8080 8181 } 8282 }
3、实现redis的增删改查:
1 1 public class TestRedis { 2 2 3 3 private Jedis jedis; 4 4 5 5 /** 6 6 * 连接redis服务器 7 7 */ 8 8 public void connectRedis() { 9 9 jedis=RedisUtil.getJedis(); 10 10 } 11 11 12 12 /** 13 13 * redis操作字符串 14 14 */ 15 15 public void testString() { 16 16 //添加数据 17 17 jedis.set("name", "youcong"); 18 18 System.out.println(jedis.get("name")); 19 19 20 20 //拼接字符串 21 21 jedis.append("name", ".com"); 22 22 System.out.println(jedis.get("name")); 23 23 24 24 //删除数据 25 25 jedis.del("name"); 26 26 System.out.println(jedis.get("name")); 27 27 28 28 //设置多个键值对 29 29 jedis.mset("name","yc","age","22","qq","1933108196"); 30 30 jedis.incr("age");//加1操作 31 31 System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" +jedis.get("qq")); 32 32 } 33 33 34 34 35 35 /** 36 36 * redis操作map集合 37 37 */ 38 38 public void testMap() { 39 39 //添加数据 40 40 Map<String,String> map = new HashMap<String,String>(); 41 41 42 42 map.put("name", "yc"); 43 43 map.put("age", "22"); 44 44 map.put("qq", "1933108196"); 45 45 jedis.hmset("user", map); 46 46 47 47 //取出users中的Name,执行结果:[minxr]-->注意结果是一个泛型的List 48 48 //第一个参数是存入redis中map对象的key,后面跟的是放入map中对象的key,后面的key可以是多个,是可变的 49 49 List<String> rsmap = jedis.hmget("user", "name","age","qq"); 50 50 System.out.println(rsmap); 51 51 52 52 53 53 //删除map中的某个键值 54 54 jedis.hdel("user", "age"); 55 55 System.out.println(jedis.hmget("user", "age"));//因为删除了,所以返回的是Null 56 56 System.out.println(jedis.hlen("user"));//返回key为user的键中存放的值的个数2 57 57 System.out.println(jedis.exists("user"));//是否存在key为user的记录,返回true 58 58 System.out.println(jedis.hkeys("user"));//返回map对象中的所有key 59 59 System.out.println(jedis.hvals("user"));//返回map对象中的所有value 60 60 61 61 Iterator<String> iter = jedis.hkeys("user").iterator(); 62 62 while(iter.hasNext()) { 63 63 String key = iter.next(); 64 64 System.out.println(key+":" + jedis.hmget("user", key)); 65 65 } 66 66 67 67 } 68 68 69 69 /** 70 70 * redis操作List集合 71 71 */ 72 72 public void testList() { 73 73 //开始前,先移除所有的内容 74 74 jedis.del("java framework"); 75 75 System.out.println(jedis.lrange("java framework", 0, -1)); 76 76 77 77 //先向key java framework 中存放三条数据 78 78 jedis.lpush("java framework","spring"); 79 79 jedis.lpush("java framework", "struts"); 80 80 jedis.lpush("java framework", "hibernate"); 81 81 82 82 //再取出所有数据jedis.lrange是按范围取出 83 83 //第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度 -1表示取得所有 84 84 System.out.println(jedis.lrange("java framework", 0, -1)); 85 85 86 86 jedis.del("java framework"); 87 87 jedis.rpush("java framework", "spring"); 88 88 jedis.rpush("java framework", "struts"); 89 89 jedis.rpush("java framework","hibernate"); 90 90 System.out.println(jedis.lrange("java framework", 0, -1)); 91 91 92 92 93 93 } 94 94 95 95 96 96 /** 97 97 * redis操作set集合 98 98 * 99 99 */ 100100 101101 public void testSet() { 102102 103103 //添加 104104 jedis.sadd("user", "liuling"); 105105 jedis.sadd("user", "xinxin"); 106106 jedis.sadd("user","ling"); 107107 jedis.sadd("user", "zhangxinxin"); 108108 jedis.sadd("user", "who"); 109109 110110 //删除 111111 jedis.srem("user", "who"); 112112 System.out.println(jedis.smembers("user"));//获取所有加入的value 113113 System.out.println(jedis.sismember("user", "who"));//判断who是否是user集合的元素 114114 System.out.println(jedis.srandmember("user")); 115115 System.out.println(jedis.scard("user"));//返回集合的元素个数 116116 } 117117 118118 119119 /** 120120 * redis排序 121121 */ 122122 123123 public void testSort() { 124124 125125 //jedis 排序 126126 //注意,此处的rpush和lpush是List的操作。是一个双向链表(但从表现来看的) 127127 jedis.del("a");//先清除数据,再加入数据进行测试 128128 jedis.rpush("a", "1"); 129129 jedis.lpush("a", "6"); 130130 jedis.lpush("a", "3"); 131131 jedis.lpush("a", "9"); 132132 System.out.println(jedis.lrange("a", 0, -1)); 133133 System.out.println(jedis.sort("a"));//[1,3,6,9] //输入排序后结果 134134 System.out.println(jedis.lrange("a", 0, -1)); 135135 } 136136 137137 138138 /** 139139 * redis连接池 140140 */ 141141 142142 public void testRedisPool() { 143143 144144 RedisUtil.getJedis().set("newname", "test"); 145145 146146 System.out.println(RedisUtil.getJedis().get("newname")); 147147 } 148148 149149 public static void main(String[] args) { 150150 TestRedis test = new TestRedis(); 151151 test.connectRedis(); 152152 test.testSort(); 153153 } 154154 }
二、关于spring-data-redis:
1. 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
2. 针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口
ValueOperations:简单K-V操作
SetOperations:set类型数据操作
ZSetOperations:zset类型数据操作
HashOperations:针对map类型的数据操作
ListOperations:针对list类型的数据操作
3. 提供了对key的“bound”(绑定)便捷化操作API,可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key,即BoundKeyOperations:
BoundValueOperations
BoundSetOperations
BoundListOperations
BoundSetOperations
BoundHashOperations
4. 将事务操作封装,有容器控制。
5. 针对数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)
JdkSerializationRedisSerializer:POJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列。是目前最常用的序列化策略。
StringRedisSerializer:Key或者value为字符串的场景,根据指定的charset对数据的字节序列编码成string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。
JacksonJsonRedisSerializer:jackson-json工具提供了javabean与json之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。【需要jackson-mapper-asl工具支持】
OxmSerializer:提供了将javabean与xml之间的转换能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存储的数据将是xml工具。不过使用此策略,编程将会有些难度,而且效率最低;不建议使用。【需要spring-oxm模块的支持】
三、Spring boot使用RestTemplate**:**
1、POM依赖:
1 1 <dependencies> 2 2 <!-- spring boot 配置 --> 3 3 <dependency> 4 4 <groupId>org.springframework.boot</groupId> 5 5 <artifactId>spring-boot-starter-web</artifactId> 6 6 </dependency> 7 7 8 8 <dependency> 9 9 <groupId>org.springframework.boot</groupId> 1010 <artifactId>spring-boot-starter-thymeleaf</artifactId> 1111 </dependency> 1212 1313 <dependency> 1414 <groupId>org.springframework.boot</groupId> 1515 <artifactId>spring-boot-starter-test</artifactId> 1616 <scope>test</scope> 1717 </dependency> 1818 1919 <dependency> 2020 <groupId>org.springframework.boot</groupId> 2121 <artifactId>spring-boot-starter-data-redis</artifactId> 2222 </dependency> 2323 </dependencies>
2、配置文件application.properties:
1 1 # Redis数据库索引(默认为0) 2 2 spring.redis.database=0 3 3 # Redis服务器地址 4 4 spring.redis.host=127.0.0.1 5 5 # Redis服务器连接端口 6 6 spring.redis.port=6379 7 7 # Redis服务器连接密码(默认为空) 8 8 spring.redis.password= 9 9 # 连接池最大连接数(使用负值表示没有限制) 1010 spring.redis.pool.max-active=8 1111 # 连接池最大阻塞等待时间(使用负值表示没有限制) 1212 spring.redis.pool.max-wait=-1 1313 # 连接池中的最大空闲连接 1414 spring.redis.pool.max-idle=8 1515 # 连接池中的最小空闲连接 1616 spring.redis.pool.min-idle=0 1717 # 连接超时时间(毫秒) 1818 spring.redis.timeout=0
3、redis操作工具类:
1 1 @Component 2 2 public class RedisService { 3 3 @Autowired 4 4 private RedisTemplate<String, String> redisTemplate; 5 5 6 6 /** 7 7 * 默认过期时长,单位:秒 8 8 */ 9 9 public static final long DEFAULT_EXPIRE = 60 * 60 * 24; 10 10 11 11 /** 12 12 * 不设置过期时长 13 13 */ 14 14 public static final long NOT_EXPIRE = -1; 15 15 16 16 17 17 18 18 19 19 public boolean existsKey(String key) { 20 20 return redisTemplate.hasKey(key); 21 21 } 22 22 23 23 /** 24 24 * 重名名key,如果newKey已经存在,则newKey的原值被覆盖 25 25 * 26 26 * @param oldKey 27 27 * @param newKey 28 28 */ 29 29 public void renameKey(String oldKey, String newKey) { 30 30 redisTemplate.rename(oldKey, newKey); 31 31 } 32 32 33 33 /** 34 34 * newKey不存在时才重命名 35 35 * 36 36 * @param oldKey 37 37 * @param newKey 38 38 * @return 修改成功返回true 39 39 */ 40 40 public boolean renameKeyNotExist(String oldKey, String newKey) { 41 41 return redisTemplate.renameIfAbsent(oldKey, newKey); 42 42 } 43 43 44 44 /** 45 45 * 删除key 46 46 * 47 47 * @param key 48 48 */ 49 49 public void deleteKey(String key) { 50 50 redisTemplate.delete(key); 51 51 } 52 52 53 53 /** 54 54 * 删除多个key 55 55 * 56 56 * @param keys 57 57 */ 58 58 public void deleteKey(String... keys) { 59 59 Set<String> kSet = Stream.of(keys).map(k -> k).collect(Collectors.toSet()); 60 60 redisTemplate.delete(kSet); 61 61 } 62 62 63 63 /** 64 64 * 删除Key的集合 65 65 * 66 66 * @param keys 67 67 */ 68 68 public void deleteKey(Collection<String> keys) { 69 69 Set<String> kSet = keys.stream().map(k -> k).collect(Collectors.toSet()); 70 70 redisTemplate.delete(kSet); 71 71 } 72 72 73 73 /** 74 74 * 设置key的生命周期 75 75 * 76 76 * @param key 77 77 * @param time 78 78 * @param timeUnit 79 79 */ 80 80 public void expireKey(String key, long time, TimeUnit timeUnit) { 81 81 redisTemplate.expire(key, time, timeUnit); 82 82 } 83 83 84 84 /** 85 85 * 指定key在指定的日期过期 86 86 * 87 87 * @param key 88 88 * @param date 89 89 */ 90 90 public void expireKeyAt(String key, Date date) { 91 91 redisTemplate.expireAt(key, date); 92 92 } 93 93 94 94 /** 95 95 * 查询key的生命周期 96 96 * 97 97 * @param key 98 98 * @param timeUnit 99 99 * @return 100100 */ 101101 public long getKeyExpire(String key, TimeUnit timeUnit) { 102102 return redisTemplate.getExpire(key, timeUnit); 103103 } 104104 105105 /** 106106 * 将key设置为永久有效 107107 * 108108 * @param key 109109 */ 110110 public void persistKey(String key) { 111111 redisTemplate.persist(key); 112112 } 113113 }
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) GETSET:GETSET可以和INCR一起使用实现支持重置的计数功能。举个例子:每当有事件发生的时候,一段程序都会调用INCR给key mycounter加1,但是有时我们需要获取计数器的值,并且自动将其重置为0。这可以通过GETSET mycounter “0”来实现;
如:
1redis> INCR mycounter 2(integer) 1 3redis> GETSET mycounter "0" 4"1" 5redis> GET mycounter 6"0"
6、redis实现的分布式锁:
1 1 @Component 2 2 @Slf4j 3 3 public class RedisLock { 4 4 5 5 @Autowired 6 6 StringRedisTemplate redisTemplate; 7 7 8 8 /** 9 9 * 加锁 1010 * @param key 1111 * @param value 当前时间 + 超时时间 1212 * @return 1313 */ 1414 public boolean lock(String key, String value){ 1515 if (redisTemplate.opsForValue().setIfAbsent(key, value)){ 1616 return true; 1717 } 1818 1919 //解决死锁,且当多个线程同时来时,只会让一个线程拿到锁 2020 String currentValue = redisTemplate.opsForValue().get(key); 2121 //如果过期 2222 if (!StringUtils.isEmpty(currentValue) && 2323 Long.parseLong(currentValue) < System.currentTimeMillis()){ 2424 //获取上一个锁的时间 2525 String oldValue = redisTemplate.opsForValue().getAndSet(key, value); 2626 if (StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)){ 2727 return true; 2828 } 2929 } 3030 3131 return false; 3232 } 3333 3434 /** 3535 * 解锁 3636 * @param key 3737 * @param value 3838 */ 3939 public void unlock(String key, String value){ 4040 4141 try { 4242 String currentValue = redisTemplate.opsForValue().get(key); 4343 if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)){ 4444 redisTemplate.opsForValue().getOperations().delete(key); 4545 } 4646 }catch (Exception e){ 4747 log.error("【redis锁】解锁失败, {}", e); 4848 } 4949 } 5050 }
四、参考资料:
https://www.cnblogs.com/youcong/p/8098881.html