🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# Redis的数据类型 ## 一、Redis的安装 可以直接去[中文官网](http://www.redis.net.cn/)中直接下载安装,进入这个网站,[点击下载](http://www.redis.cn/download.html),下载稳定版的即可。将该tar包下载后加压到一个没有中文字符路径的空文件夹中,即可直接使用,不用进行额外的配置。本地使用方式如下: 1. 打开redis-server.exe:这是一个redis的服务器端,相当于mysql软件 2. 打开redis-cli.ext:这是一个redis的客户端,可以供我们在本地操作redis数据库,类似与图形化界面,当然这里是使用命令行的方式操作redis数据库的。 例如:在redis-cli客户端中保存键为“name",值为”zhangsan"的一条数据,并获取该数据(相当于name=zhangsan) ![](https://img.kancloud.cn/c1/be/c1be7d60e15776533295884108fa72ed_1067x145.png) &nbsp; ## 二、Redis的数据类型 Redis底层是由C语言编写的,redis里面内置的数据结构即是用C语言的结构体实现的。有五种基础的数据类型,在redis6之后新增了三种。 > 值得说明的是这里的数据结构指的是值的类型,redis的键都是有字符串构成的。 ### 2.1 数据类型分类 1. string:字符串类型; 2. hash:哈希类型,相当于map类型,值也是以键值对的形式存在的; 3. list:列表类型,可以支持重复性的数据; 4. set:集合类型,与list的区别是不支持重复性的数据; 5. sortedset:有序集合类型,在不支持重复的同时还保证数据是有序的。 6. Bitmaps:位图 7. HyperLogLog: 8. Geographic: #### string * 存储数据: > set key value * 取出数据: > get key * 删除键: > del key ~~~  127.0.0.1:6379> set username zhangsan // 设置username的值为zhangsan  127.0.0.1:6379> get username //取出username对应的值  "zhangsan"  127.0.0.1:6379> del username //username的值将会被删除 ~~~ &nbsp; #### hash类型 * 存储数据: > hset key field value 即创建一个类型为hash,其键为key,里面有个字段为field,值为value,相当于{"key": {"filed":value}} * 取出数据: > hget key field 获取字段field中的值 * 取出hash中键值key的所有的字段数据: > hgetall key 将会获取键值对,field=value * 删除字段: > hdel key field 删除键key的字段field ~~~  127.0.0.1:6379> hset person name zhangsan  127.0.0.1:6379> hset person age 21  // 即相当于创建了:person = {"name":"张三", "age":21}  127.0.0.1:6379> hget person name  "zhangsan"  127.0.0.1:6379> hgetall person  "name"  "zhangsan"  "age"  21  127.0.0.1:6379> hdel person name // 删除字段name ~~~ &nbsp; #### list类型 可以选择将一个元素添加到头部还是到尾部,很像一个双端队列结构 * 存储数据: > lpush key value //将数据从左边添加到列表中 > rpush key value //将数据从右边添加到列表中 * 取出数据: > lrange key start end 将start到end范围的索引的数据取出,从0开始,-1表示后一个元素 * 移除数据: > lpop key //删除列表中最左边的元素,并将元素返回 > rpop key //删除列表中最右边的元素,并将元素返回 ~~~  127.0.0.1:6379>lpush userlist zhangsan  127.0.0.1:6379>rpush userlist lisi  127.0.0.1:6379>lrange userlist 0 -1 //取出列表中所有的元素  "zhangsan"  "lisi"  127.0.0.1:6379>lpop userlist  "zhangsan"  127.0.0.1:6379>rpop userlist  "lisi" ~~~ &nbsp; #### set类型 与list类型类似,但是不会添加重复数据 * 存储数据: > sadd key value * 获取数据: > smembers key 取出所有的值 * 删除数据: > srem key value ~~~  127.0.0.1:6379>sadd myset a //给myset中添加"a"  127.0.0.1:6379>sadd myset b  127.0.0.1:6379>smembers myset  "a"  "b"  127.0.0.1:6379>srem myset a //删除a的值 ~~~ &nbsp; #### sortedset类型 有序集合类型,不允许重复数据,存储数据时要为每个值设置一个double类型的score(分数)用来排序 * 存储数据: > zadd key score value * 取出数据: > zrange key start end \[withscores\] 可选的withscores表示是否要将分数一起展示出来,起始索引下标为0,-1表示最后一个元素 * 删除数据: > zrem key value ~~~  127.0.0.1:6379> zadd mysort 60 zhangsan //值zhangsan的score为60  (integer) 1  127.0.0.1:6379> zadd mysort 50 lisi //值lisi的score为50  (integer)1  127.0.0.1:6379> zadd mysort 80 wangwu //值wangwu的score为80  (integer) 1  127.0.0.1:6379> zrange mysort 0 -1  1) "lisi"  2) "zhangsan"  3) "wangwu"  127.0.0.1:6379> zrange mysort 0 -1 withscores  1) "zhangsan"  2) "60"  3) "wangwu"  4) "80"  5) "lisi"  6) "500"  127.0.0.1:6379> zrem mysort lisi //删除lisi的值  (integer) 1 ~~~ &nbsp; #### Bitmaps bitmaps(位图)严格上讲并不是新的一种数据类型,而是定义了字符串类型面向位的一组操作。通过在不同位上设置0或者1来存储不同的状态。 1. 创建位图对象的命令 ~~~  localhost:6379>setbit key offset value ~~~ offset为偏移量,表示要将哪一位设置成0/1。 2. 获取某一位的状态命令 ~~~  localhost:6379>getbit key offset ~~~ offset为偏移量。返回值为0或者1。对没有设置的位都会返回0。 3. 统计为1的个数 ~~~  localhost:6379>bitcount key ~~~ 或者是 ~~~  localhost:6379>bitcount key 0, 1 ~~~ 这样可以获取`字节`0和1中位为1的个数。 4. 两个key之间进行逻辑运算 ~~~  localhost:6379>bitop operate destkey key1 key2 ~~~ operate可选类型为:and,or,xor等逻辑运算。 5. 找到第一指定为0或者1的位 ~~~  localhost:6379>bitpos key 0/1 [start] [end] ~~~ > 应用场景 1. 可以用在统计网站的日活跃用户。 2. 各种实时分析,例如和对象ID相关的,可以将对象的ID的大小表示为第几位,进而统计相关的信息。 &nbsp; #### HyperLogLog 是一种概率数据结构,用来统计一个集合中的基数。当数据的量特别大的时候,使用HyperLogLog就可以节省大量的内存,HyperLogLog使用的是固定的大小存储基数,为12KB,可以统计2^64个数据。Redis中统计出来的结果可能与实际的有1%的偏差。 1. 创建: ~~~  localhost:6379>pfadd key value ~~~ 基数增加成功会返回1,否则返回0. 2. 统计基数数量: ~~~  localhost:6379>pfcount key ~~~ ![](https://img.kancloud.cn/ec/d8/ecd8155bff1ae6137cefea40f8dbe480_843x66.png) 集合{1,2,3, 4, 1, 1, 1, 1} 统计出来的基数就是4。 3. 合并两个HyperLogLog类型 ~~~  localhost:6379>pfmerge key key1 key2 ~~~ > 应用场景 1. 统计网站的页面访问量。 2. 统计独立访客的数量。 &nbsp; #### Geographic 地图的坐标类型,可以设置经纬度,查询,范围查询的等操作。 1. 创建 ~~~  geoadd key 经度 纬度 地点 ~~~ 2. 获取: ~~~  geopos key 地点 ~~~ 3. 获取两个地点的直线距离 ~~~  geodist key 地点1 地点2 显示单位 ~~~ 显示单位的可取值为: `km,m,mi(英里),ft(英尺)`。 4. 获取一定范围内的数据: ~~~ georadius key 经度 纬度 半径长度 显示单位 ~~~ &nbsp; ### 2.2 其他通用命令操作 * keys \* :查询所有键,可以使用正则表达式的方式 * type key:查询该键的类型 * del key:删除指定的键 &nbsp; ## 三、java操作Redis ~~~ java使用Jedis工具来操作redis数据库。如果还没有下载Jedis相关的jar的话,可以到<a href="https://jar-download.com/artifacts/redis.clients/jedis/3.3.0">这里下载</a>。或者如果是使用maven的话,可以在pom.xml配置如下引入相关依赖 ~~~ ~~~ <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.1</version> </dependency> ~~~ (版本号可以选择自己想要) ### 3.1使用方式 Jedis的使用非常简便,只要创建对应的Jedis对象即可。 ~~~ Jedis jedis = new Jedis("localhost", 6379); //连接本地的Jedis数据库,无参构造的话默认就是这两个值 注意要将本地的redis服务端打开 jedis.set("name", "zhangsan"); //设置一个字符串类型的数据 name=zhangsan jedis.get("name"); // zhangsan ~~~ jedis中对数据操作的那些方法的方法名是和上面将的redis中的命令是一致的,只是Jedis中命名是驼峰命名,有一些名称可能要区分一下大小写。例如 ~~~ jedis.hset("user", "name", "zhangsan"); //设置一个map数据 jedis.hset("user", "age", "22"); jedis.hget("user", "name"); jedis.hgetAll("user"); ~~~ 可见其使用方式和命名行的使用方式是类似的,只不过把数据当成参数进行传递,就不在这里过多赘述了。 其他方法: ~~~ jedis.close(); //关闭连接jedis.setex(String key, int seconds, String value); //设置seconds秒数之后自动删除该键值对 ~~~ ### 3.2 连接池 与mysql类似的,redis也有一个数据连接池对象为JedisPool,下面创建一个redis数据库连接的工具类,用于获取JedisPool连接池和获取Jedis连接对象。 ~~~ import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public final class JedisUtil { /** * JedisPool连接池对象 */ private static JedisPool jedisPool; static { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(50); //最大连接数,设置为0表示没有限制 config.setMaxIdle(10); //最大等待的连接数,设置为0表示没有限制 jedisPool = new JedisPool(config, "localhost", 6379); } /** * 获取Jedis连接对象 */ public static Jedis getJedis() { return jedisPool.getResource(); } /** * 关闭jedis连接 */ public static void close(Jedis jedis) { if (jedis != null) { jedis.close(); } } } ~~~ ### 3.3 与Spring Boot整合 1. 引入依赖 ~~~ <!-- 整合redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- spring2.x版本集成redis所需common-pool2 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> ~~~ 2. application.yml中配置属性 ~~~ spring: # redis配置 redis: host: localhost port: 6379 database: 0 # 数据库索引,默认为0 timeout: 1800000 # 连接超时时间 lettuce: pool: max-active: 20 # 连接池中的最大连接数,负值表示没有限制 max-wait: 1 # 连接池中的最大等待数 max-idle: 5 # 连接池中的最大空闲数 min-idle: 0 # 连接池中的最小空闲数 ~~~ 3. 书写Redis配置类 ~~~ @EnableCaching @Configuration public class RedisConfig extends CachingConfigurerSupport { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); RedisSerializer<String> redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); redisTemplate.setConnectionFactory(redisConnectionFactory); // 设置key的序列化方式 redisTemplate.setKeySerializer(redisSerializer); // 设置值的序列化方式 redisTemplate.setValueSerializer(redisSerializer); return redisTemplate; } @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisSerializer<String> redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); // 解决查询缓存转换异常的问题 ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); // 配置序列化,解决乱码问题,过期时间设置为10分钟 RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofSeconds(600)) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) .disableCachingNullValues(); RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory) .cacheDefaults(configuration) .build(); return redisCacheManager; } } ~~~ `配置类的内容都差不多。` 4. 注入RedisTemplate对象 ~~~ @Autowried private RedisTemplate redisTemplate; ~~~ ## 四、概念补充 Redis(Remote Dictionary Server),即远程字典服务,是一款有**C语言开发**的,**高性能**的NOSQL系列的存储**键值对**类型的数据库。 NoSQL:not only sql,不仅仅是sql,指的是一种非关系型数据库,区别于mysql这种关系型数据库,能够处理大规模的数据和高并发的场景。 注意redis并不是用来替代关系型数据库,是用来在某些特定的场合下能和关系型数据库相互补充。例如,在一些需要频繁从数据库获取相同的数据的场合中,在第一次读取数据时,可以先将数据从mysql读取,同时保存在redis数据库中,之后再读取时直接从redis数据库中读取。 ### 4.1常用的NoSQL系列的数据库 **键值对系列** * 相关产品:Redis, Voldemort, Berkeley DB等 * 使用场景:内容缓存,主要用于处理大量数据的高访问负载为题。 * 数据存储类型:键值对,key-value,value是非结构化的。 **列存储数据库** * 相关产品:HBase,Riak,Cassandra * 使用场景:分布式的文件系统 * 数据存储类型:以列簇式存储,将一列数据放在一起 **文档型数据库** * 相关产品:MongoDB, CouchDB * 使用场景:web应用 * 数据存储类型:一系列键值对,与key-value类似,但是value是结构化的。 **图形数据库** * 相关产品:Noe4J, InfoGrid, Infinite Graph * 使用场景:社交网络 * 数据存储类型:图结构 ### 4.2 Redis的使用场景 1. 缓存:数据查询,新闻内容,短连接,商品内容, 可以让数据只从关系型数据库中获取一次,之后从缓存中获取将会大大加快速度 2. 聊天室在线好友列表 3. 任务队列,例如秒杀操作,抢购(12306) 4. 排行榜 5. 网站访问统计 6. 数据过期处理,可以精确到毫秒值 7. 分布式集群架构中的session分离