Redis 基础入门

本贴最后更新于 1463 天前,其中的信息可能已经时移世改

非关系型数据库 redis

1. 基本命令

1. set key value # 设置键 值 2. flushall # 清除所有数据库的值 3. keys * # 查看所有的键 4. exists key # 判断是否存在这个key 5. select index # 根据index切换数据库 从0到15 默认 6. move key index # 将key移动到数据库index中 7. expire key seconds # 设置key在多少秒之后过期 8. flushdb # 清空当前数据库的值

2. 五大数据类型

Redis-Key
String
127.0.0.1:6379[1]> set name wuhobin OK 127.0.0.1:6379[1]> append name "hello" # 向key中追加 如果追加的key不存在就相当于set (integer) 12 127.0.0.1:6379[1]> get name "wuhobinhello" 127.0.0.1:6379[1]> expire name 10 # 设置key过期的时间 (integer) 1 127.0.0.1:6379[1]> strlen name # 获取key的字符串的长度 (integer) 7 127.0.0.1:6379[1]> get views "0" 127.0.0.1:6379[1]> incr views # 让当前key加1 (integer) 1 127.0.0.1:6379[1]> get views "1" 127.0.0.1:6379[1]> decr views # 让当前key减去1 (integer) 0 127.0.0.1:6379[1]> get views "0" 127.0.0.1:6379[1]> incrby views 10 # 让当前key自增 每次增加10 (integer) 10 127.0.0.1:6379[1]> get views "10" 127.0.0.1:6379[1]> decrby views 10 #让当前key自减 每次减去10 (integer) 0 127.0.0.1:6379[1]> get views "0" 127.0.0.1:6379[1]> set name helloword OK 127.0.0.1:6379[1]> getrange name 0 5 # 截取字符串 [0,5] "hellow" 127.0.0.1:6379[1]> setrange name 0 xxx # 替换 把之前的字符串的0的位置替换为xxx (integer) 9 127.0.0.1:6379[1]> get name "xxxloword" 127.0.0.1:6379[1]> setex key 30 hello # 设置key过期时间为30秒 值为hello OK 127.0.0.1:6379[1]> ttl key # 查看key还有多少时间过去 (integer) 27 127.0.0.1:6379[1]> get key "hello" 127.0.0.1:6379[1]> setnx mykey hello # set if not exist 当mykey不存在时设置mykey的值为hello 如果成功 返回1 (integer) 1 127.0.0.1:6379[1]> mset k1 v1 k2 v2 k3 v3 # 同时设置多个值 OK 127.0.0.1:6379[1]> keys * 1) "k3" 2) "k1" 3) "k2" 127.0.0.1:6379[1]> set user:1 {name:wuhobin,age:20,girFirend:sunsi} # 设置一个user:1对象,值为json字符来保存一个对象 OK 127.0.0.1:6379[1]> get user:1 "{name:wuhobin,age:20,girFirend:sunsi}" 127.0.0.1:6379[1]>
List
# redis的列表相当于是一个双端队列 lpush从上边入栈 rpush从下边入栈 127.0.0.1:6379[1]> lpush list one # 向列表list里面添加one元素 (integer) 1 127.0.0.1:6379[1]> lpush list two # 向列表list里面添加two元素 (integer) 2 127.0.0.1:6379[1]> lpush list three # 向列表list里面添加three元素 (integer) 3 127.0.0.1:6379[1]> lrange list 0 4 1) "three" 2) "three" 3) "two" 4) "one" 127.0.0.1:6379[1]> lrem list 1 three # 从列表中移除一个值为three的元素 (integer) 1 127.0.0.1:6379[1]> lrange list 0 4 1) "three" 2) "two" 3) "one"
Set
127.0.0.1:6379[1]> sadd list hello # 向集合中添加元素 (integer) 1 127.0.0.1:6379[1]> sadd list hello (integer) 0 127.0.0.1:6379[1]> sadd list wuhobin (integer) 1 127.0.0.1:6379[1]> smembers list # 查看集合里有哪些元素 1) "hello" 2) "wuhobin" 127.0.0.1:6379[1]> 127.0.0.1:6379[1]> 127.0.0.1:6379[1]> sismember list hello # 看集合里面是否有hello 如果有返回1 否则返回0 (integer) 1 127.0.0.1:6379[1]> sismember list sss (integer) 0 127.0.0.1:6379[1]> scard list # 获取集合里面的个数值 (integer) 2 127.0.0.1:6379[1]> srem list hello # 从集合里移除某个元素 (integer) 1 127.0.0.1:6379[1]> srandmember list # 从集合中随机获取一个元素 "wuhobin" 127.0.0.1:6379[1]> spop list # 从集合里随机弹出一个元素 "wuhobin"
Hash

key-Map key 里面存的是 map 集合

127.0.0.1:6379[1]> hset myhash name wuhobin # 向hash中存值 以键值对的方式 (integer) 1 127.0.0.1:6379[1]> hset myhash age 21 (integer) 1 127.0.0.1:6379[1]> hget myhash name # 从hash中取值 "wuhobin"
Zset
127.0.0.1:6379[1]> zadd salary 2500 wuhobin # 向有序集合中添加元素 (integer) 1 127.0.0.1:6379[1]> zadd salary 500 sunsi (integer) 1 127.0.0.1:6379[1]> ZRANGEBYSCORE salary -inf +inf # 根据添加时的标识从小到大排序 -inf负无穷 1) "sunsi" 2) "cy" 3) "wuhobin" 127.0.0.1:6379[1]> ZRANGEBYSCORE salary -inf +inf withscores # 排序并且附带标识 1) "sunsi" 2) "500" 3) "cy" 4) "2000" 5) "wuhobin" 6) "2500" 127.0.0.1:6379[1]> zrange salary 0 -1 1) "sunsi" 2) "cy" 3) "wuhobin" 127.0.0.1:6379[1]> zrem salary sunsi # 移除某一元素 (integer) 1 127.0.0.1:6379[1]> zrange salary 0 -1 1) "cy" 2) "wuhobin"

3. 三种特殊数据类型

geospatial

地理空间,地理位置,朋友圈,附近的人,距离,方圆半径的人

127.0.0.1:6379> geoadd ching:city 114.05 22.52 shenzhen # 添加地理位置 参数 key 经度 纬度 城市 (integer) 1 127.0.0.1:6379> geoadd china:city 160.16 30.24 hangzhou1 (integer) 1 127.0.0.1:6379> geoadd china:city 108.96 34.26 xian (integer) 1 127.0.0.1:6379> geopos china:city shanghai # 查看某个城市的地理位置 1) 1) "116.00000113248825073" 2) "45.00000100864581043" 127.0.0.1:6379> zrange china:city 0 -1 # 查看所有的元素 1) "shanghai" 2) "shanghai1" 3) "shanghai2" 127.0.0.1:6379> GEORADIUS china:city 114 66 10000 km withcoord # 返回114 66半径1000km之内的地理位置的集合 1) 1) "shanghai" 2) 1) "116.00000113248825073" 2) "77.99999963605176845" 2) 1) "shanghai1" 2) 1) "116.00000113248825073" 2) "77.99999963605176845" 3) 1) "shanghai2" 2) 1) "116.00000113248825073" 2) "77.99999963605176845" 127.0.0.1:6379>
Hyperglog

基数统计的算法, 可以统计一个 key 里面不重复元素的个数

127.0.0.1:6379> PFADD ket1 1 122 2 3 4 4 1 14 4 5 3 # 添加元素 (integer) 1 127.0.0.1:6379> PFCOUNT ket1 # 查看集合的不重复元素的个数 (integer) 7 127.0.0.1:6379> PFMERGE ket3 ket1 ket2 # 合并两个key 求并集 OK 127.0.0.1:6379> PFCOUNT ket3 (integer) 14
Bitmaps

统计用户信息 活跃 不活跃 登陆 未登陆 365 天打卡

位图 数据结构 都是操作二进制数来进行记录 就只有 0 和 1 两个状态

4. 事务

原子性: 要么同时成功, 要么同时失败

Redis 事务本质 : 一组命令的集合! 一个事物中的所有命令都会被序列化, 在事务执行的过程中,会按照顺序执行

Redis 单条命令是保证原子性的,事务是不保证原子性的

127.0.0.1:6379> multi # 开启事务 OK 127.0.0.1:6379(TX)> 127.0.0.1:6379(TX)> 127.0.0.1:6379(TX)> set k1 v1 # 命令入队 QUEUED 127.0.0.1:6379(TX)> set k2 v2 QUEUED 127.0.0.1:6379(TX)> set k3 v3 QUEUED 127.0.0.1:6379(TX)> exec # 执行事务 1) OK 2) OK 3) OK

编译有错误 代码错误 事务中所有的命令都不会执行

5. 悲观锁 乐观锁

悲观锁 : 认为无论干什么都会出问题, 无论做什么都会加锁

乐观锁 : 认为做什么都不会出现问题, 所以不会加锁

redis 的监测测试

127.0.0.1:6379> set money 100 OK 127.0.0.1:6379> set out 0 OK 127.0.0.1:6379> watch money # 监视money OK 127.0.0.1:6379> multi # 开启事务 OK 127.0.0.1:6379(TX)> decrby money 20 QUEUED 127.0.0.1:6379(TX)> incrby out 20 QUEUED 127.0.0.1:6379(TX)> exec 1) (integer) 80 2) (integer) 20

当前开了两个线程, 一个线程监视一个线程改动

# 改动money 127.0.0.1:6379> get money "80" 127.0.0.1:6379> set money 1000 OK

使用 watch 在这里相当于乐观锁的操作

# 当前线程实现监控 127.0.0.1:6379> watch money OK 127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> DECRby money 10 QUEUED 127.0.0.1:6379(TX)> incrby out 10 QUEUED 127.0.0.1:6379(TX)> exec # 当监视到另外一个线程导致了money的值发生了改变时, 再执行事务将会执行失败 (nil)

6. Springboot 整合 redis

  1. 添加 springboot 关于 redis 的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
  1. 在真实 java 开发中,我们一般都以 json 的格式来传递对象,所以在项目中都会让实体类来实现 Serializable 接口实现序列化,默认的 redisTemplate 的序列化是使用的 jdk 序列化, 获得的 key 名会乱码

    image-20210317185058880

这里我们需要自定义 redisTemplate,设置不同的序列化方式

@Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(factory); // 序列化配置 Jackson2JsonRedisSerializer<Object> objectJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); objectJackson2JsonRedisSerializer.setObjectMapper(om); // String 序列化 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key也采用string的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson template.setValueSerializer(objectJackson2JsonRedisSerializer); // hash的value采用jackson template.setHashValueSerializer(objectJackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } }

自定义 redisUtils 工具类

@Component public class RedisUtils { @Autowired private RedisTemplate<String, Object> redisTemplate; // ===============common==================== /** * 指定缓存的失效时间 * @param key * @param time * @return */ public boolean expire(String key,long time){ try { if(time > 0 ){ redisTemplate.expire(key,time, TimeUnit.SECONDS); } return true; }catch (Exception e){ e.printStackTrace(); return false; } } /** * 根据key 获取过期时间 * @param key 键 不能为null * @return 时间(秒) 返回0代表为永久有效 */ public long getExpire(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); } /** * 判断key是否存在 * @param key 键 * @return true 存在 false不存在 */ public boolean hasKey(String key) { try { return redisTemplate.hasKey(key); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 删除缓存 * @param key 可以传一个值 或多个 */ @SuppressWarnings("unchecked") public void del(String... key) { if (key != null && key.length > 0) { if (key.length == 1) { redisTemplate.delete(key[0]); } else { redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key)); } } } // ============================String============================= /** * 普通缓存获取 * @param key 键 * @return 值 */ public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } /** * 普通缓存放入 * @param key 键 * @param value 值 * @return true成功 false失败 */ public boolean set(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 普通缓存放入并设置时间 * @param key 键 * @param value 值 * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 * @return true成功 false 失败 */ public boolean set(String key, Object value, long time) { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else { set(key, value); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 递增 * @param key 键 * @param delta 要增加几(大于0) * @return */ public long incr(String key, long delta) { if (delta < 0) { throw new RuntimeException("递增因子必须大于0"); } return redisTemplate.opsForValue().increment(key, delta); } /** * 递减 * @param key 键 * @param delta 要减少几(大于0) * @return */ public long decr(String key, long delta) { if (delta < 0) { throw new RuntimeException("递减因子必须大于0"); } return redisTemplate.opsForValue().increment(key, -delta); } // ================================Map================================= /** * HashGet * @param key 键 不能为null * @param item 项 不能为null * @return 值 */ public Object hget(String key, String item) { return redisTemplate.opsForHash().get(key, item); } /** * 获取hashKey对应的所有键值 * @param key 键 * @return 对应的多个键值 */ public Map<Object, Object> hmget(String key) { return redisTemplate.opsForHash().entries(key); } /** * HashSet * @param key 键 * @param map 对应多个键值 * @return true 成功 false 失败 */ public boolean hmset(String key, Map<String, Object> map) { try { redisTemplate.opsForHash().putAll(key, map); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * HashSet 并设置时间 * @param key 键 * @param map 对应多个键值 * @param time 时间(秒) * @return true成功 false失败 */ public boolean hmset(String key, Map<String, Object> map, long time) { try { redisTemplate.opsForHash().putAll(key, map); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 向一张hash表中放入数据,如果不存在将创建 * @param key 键 * @param item 项 * @param value 值 * @return true 成功 false失败 */ public boolean hset(String key, String item, Object value) { try { redisTemplate.opsForHash().put(key, item, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 向一张hash表中放入数据,如果不存在将创建 * @param key 键 * @param item 项 * @param value 值 * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 * @return true 成功 false失败 */ public boolean hset(String key, String item, Object value, long time) { try { redisTemplate.opsForHash().put(key, item, value); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 删除hash表中的值 * @param key 键 不能为null * @param item 项 可以使多个 不能为null */ public void hdel(String key, Object... item) { redisTemplate.opsForHash().delete(key, item); } /** * 判断hash表中是否有该项的值 * @param key 键 不能为null * @param item 项 不能为null * @return true 存在 false不存在 */ public boolean hHasKey(String key, String item) { return redisTemplate.opsForHash().hasKey(key, item); } /** * hash递增 如果不存在,就会创建一个 并把新增后的值返回 * @param key 键 * @param item 项 * @param by 要增加几(大于0) * @return */ public double hincr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, by); } /** * hash递减 * @param key 键 * @param item 项 * @param by 要减少记(小于0) * @return 285 */ public double hdecr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, -by); } // ============================set============================= /** * 根据key获取Set中的所有值 * @param key 键 * @return */ public Set<Object> sGet(String key) { try { return redisTemplate.opsForSet().members(key); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 根据value从一个set中查询,是否存在 * @param key 键 * @param value 值 * @return true 存在 false不存在 */ public boolean sHasKey(String key, Object value) { try { return redisTemplate.opsForSet().isMember(key, value); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将数据放入set缓存 * @param key 键 * @param values 值 可以是多个 * @return 成功个数 */ public long sSet(String key, Object... values) { try { return redisTemplate.opsForSet().add(key, values); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 将set数据放入缓存 * @param key 键 * @param time 时间(秒) * @param values 值 可以是多个 * @return 成功个数 */ public long sSetAndTime(String key, long time, Object... values) { try { Long count = redisTemplate.opsForSet().add(key, values); if (time > 0) expire(key, time); return count; } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 获取set缓存的长度 * @param key 键 * @return */ public long sGetSetSize(String key) { try { return redisTemplate.opsForSet().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 移除值为value的 * @param key 键 * @param values 值 可以是多个 * @return 移除的个数 */ public long setRemove(String key, Object... values) { try { Long count = redisTemplate.opsForSet().remove(key, values); return count; } catch (Exception e) { e.printStackTrace(); return 0; } } // ===============================list================================= /** * 获取list缓存的内容 * @param key 键 * @param start 开始 * @param end 结束 0 到 -1代表所有值 * @return */ public List<Object> lGet(String key, long start, long end) { try { return redisTemplate.opsForList().range(key, start, end); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 获取list缓存的长度 * @param key 键 * @return */ public long lGetListSize(String key) { try { return redisTemplate.opsForList().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 通过索引 获取list中的值 * @param key 键 * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 * @return */ public Object lGetIndex(String key, long index) { try { return redisTemplate.opsForList().index(key, index); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 将list放入缓存 * @param key 键 * @param value 值 * @return */ public boolean lSet(String key, Object value) { try { redisTemplate.opsForList().rightPush(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将list放入缓存 * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ public boolean lSet(String key, Object value, long time) { try { redisTemplate.opsForList().rightPush(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /*** 将list放入缓 * @param key 键 * @param value 值 * @return */ public boolean lSet(String key, List<Object> value) { try { redisTemplate.opsForList().rightPushAll(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将list放入缓 * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ public boolean lSet(String key, List<Object> value, long time) { try { redisTemplate.opsForList().rightPushAll(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根据索引修改list中的某条数据 * @param key 键 * @param index 索引 * @param value 值 * @return 509 */ public boolean lUpdateIndex(String key, long index, Object value) { try { redisTemplate.opsForList().set(key, index, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 移除N个值为value * @param key 键 * @param count 移除多少个 * @param value 值 * @return 移除的个数 */ public long lRemove(String key, long count, Object value) { try { Long remove = redisTemplate.opsForList().remove(key, count, value); return remove; } catch (Exception e) { e.printStackTrace(); return 0; } } }
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    286 引用 • 248 回帖 • 14 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • ieras via iPhone

    整理的很不错呀!