- 一、什么是 NoSQL?
- 二、Redis 简介
- 2.1 什么是Redis?应用场景?
- 2.2 Redis 优点/应用场景
- 2.3 CentOS7安装 Redis
- 2.3 安装
- 2.3.1 前端启动(了解)
- 2.3.2 后端启动(重点)
- 2.3.3 客户端连接(掌握)
- 2.3.4 远程访问 Redis 服务器
- 2.3.5 设置redis密码
- 三、Redis 的数据结构
- 3.1 String
- 3.2 List
- 3.3 Set
- 3.4 ZSet
- 3.5 Hash
- 四、Java 操作Redis
- 五、Spring Boot 使用Redis
- 5.1 引入依赖
- 5.2 application.yml配置redis
- 5.3 自定义 Redis 配置类
- 5.4 调用 RedisTemplate 的 API
- 六、Spring session(session共享)
- 6.1 引入依赖
- 6.2 application.yml配置spring session
- 6.3 @EnableRedisHttpSession注解
- 6.4 测试的类
- 6.5 更改 Spring Session的序列化器
- 5.5 Nginx负载均衡查看session共享
- 七、Redis工具类(自定义功能)
NoSQL(Not only SQL),“不仅仅是 SQL”, 泛指非关系型的数据库。NoSQL 不依赖业务逻辑方式存储,而以简单的 key-value 模式存储。因此大大的增加了数据库的扩展能力。
NoSQL 的代表
NoSQL 的存储格式可以是列式存储,key-value 存储,文档存储,各自的代表产品如下:
1)键值存储: Redis
2)列式存储: Hbase
3)文档型存储: MongoDB
Redis 是一个高性能的(key/value)分布式内存数据库,基于内存运行 并支持持久化的NoSQL数据库,是当前最热门的NoSql数据库之一, 也被人们称为数据结构服务器。Redis 是一个开源(BSD 许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(string), 散列(hash), 列表(list), 集合(set), 有序集合(sorted set)。
Redis 性能极高 – Redis 能读的速度是 110000 次/s,写的速度是 81000 次/s 。
优点:
Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。 Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储 Redis支持数据的备份,即 master-slave模式的数据备份 。
应用场景:
内存存储和持久化:redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务 取最新N个数据的操作,如: 可以将最新的10条评论的ID放在Redis的List集合里面 模拟类似于HttpSession这种需要设定过期时间的功能 发布、 订阅消息系统 定时器、计数器 。查看详细应用场景
1) 上传安装包到 Linux;
2) 解压到自己指定的目录;(我这里解压到 /root/javaDevEnv/modules)
3) cd到 /root/javaDevEnv/modules/redis目录,输入make 命令执行编译命令,接下来控制台会输出各种编译过程中输出的内容。(提示:安装 redis 需要先将官网下载的源码进行编译,编译依赖 gcc 环境,如果没有 gcc 环境,要先安装 gcc-c++(c 语言的环境),命令: yum -y install gcc-c++ 。如果已安装,可通过 gcc --version 查看版本。)
4) 安装;(在 redis 所在的目录执行命令)(执行完命令后会在redis的目录中生成一个bin目录,该目录中存放redis相关的重要的可执行文件)
make PREFIX=/root/javaDevEnv/modules/redis install
2.3.1 前端启动(了解)【提示】
- 这里多了一个关键字 PREFIX= 这个关键字的作用是编译的时候用于指定程序存放的路径。比如我们现在就是指定了redis必须存放在/root/javaDevEnv/modules/redis目录。假设不添加该关键字Linux会将可执行文件存放在/usr/local/bin目录,库文件会存放在/usr/local/lib目录。配置文件会存放在/usr/local/etc目录。其他的资源文件会存放在usr/local/share目录。这里指定目录主要是为了后期维护方便。
在 bin 目录下执行 redis-server 即可启动服务器,会带 1 个界面。缺点是启动后,不能再进行其它操作。如要做其它操作,必须使用 Ctrl+C,此时 redis-server 结束,客户端就不能连接了。
1) 修改redis.conf 配置文件
2) 执行 bin 下的 redis-server 时,带上 redis.conf 。
2.3.3 客户端连接(掌握)【提示】
- 开启服务器:在 redis 目录下可使用 ./bin/redis-server redis.conf 来后台开启Redis服务器。
- 关闭服务器:在 redis 目录下可使用 ./bin/redis-cli shutdown 来关闭Redis服务器。
- 查看Redis服务器进程:ps -aux | grep redis。
- 端口监听查看:netstat -lanp | grep 6379。
bin 目录下有 redis 的客户端,即 redis-cli(Redis Command Line Interface),它是 Redis 自带的基于命令行的 Redis 客户端。
执行 bin/redis-cli 即可连接(登录)redis 服务器。(quit命令或exit命令可退出终端)
如果希望远程连接其它主机或者其它端口的 Redis 服务器,可以加上相应的参数,使用-h 设置远程主机的 ip,使用-p 设置远程主机的端口号。
redis-cli 连上 redis 服务后,可以在命令行向 Redis 服务器发送命令。比如 PING 命令用来测试客户端与 Redis 服务器的连接是否正常,如果连接正常会收到回复 PONG。
1) 开放端口 6379;
# 开启6379端口【然后重启防火墙,使放行的端口生效】 firewall-cmd --zone=public --add-port=6379/tcp --permanent # 重启防火墙 firewall-cmd --reload
【提示】
- 查看开启的端口列表:firewall-cmd --list-ports;
2) 修改配置文件 redis.conf ,一、注释掉 bind 127.0.0.1(任何 ip 都能远程连接 redis)。二、找到 protected-mode 这行, 将值 yes 改为 no。
【提示】
- 可以输入“/protected-mode”在文件里搜索,改完后保存并退出。
3) 使用图形化工具连接redis服务器。
首先要启动 redis 服务器。
[root@localhost redis]# ./bin/redis-server redis.conf
2.3.5 设置redis密码【提示】
- 关闭redis服务器:./bin/redis-cli shutdown。
三、Redis 的数据结构【提示】后期补充。
Redis 中 key 是 String 类型,value 根据存储数据不同,有如下类型:
| value 的数据类型 | 说明 |
|---|---|
| String | 字符串,最简单的 k-v 存储。 |
| List | 简单的 list,顺序列表,支持首位或者末尾插入数据。 |
| Set | 无序 list,查找速度快,适合交集、并集、差集处理。 |
| Sorted Set | 有序的 Set。 |
| Hash | hash 格 式 , value 为 field-value , 适合ID-Detail 这样的场景。 |
点击该博主查看该图片
| 命令 | 说明 |
|---|---|
| keys * | 查找所有的key。(包括string,hash,list,set,zset) |
| del key[key ...] | 删除指定key。 |
| `` | |
| `` | 更多命令可查看:www.redis.cn |
String 是 redis 最基本的类型,一个 key 对应一个 value。String 类型是二进制安全的。意思是 redis 的 String 可以包含任何数据。比如jpg图片或者序列化的对象。
String 类型是 Redis 最基本的数据类型,String 类型的值最大能存储 512MB。
| 命令 | 说明 |
|---|---|
| set key value | 设定 key 持有指定的字符串 value,如果该 key 存在则进行覆盖操作。总是返回”OK”。 如果value中含有空格的话可以使用单引号''将整个value括起来。 |
| get key | 获取 key 的 value。 如果与该 key 关联的 value 不是 String 类型,redis将返回错误信息。 如果该 key 不存在,返回 null。 |
| incr key | 将指定的 key 的 value 原子性的递增 1。 如果该 key 不存在,其初始值为 0,在 incr 之后其值为 1。 如果 value 的值不能转成整型,如 hello,该操作将执行失败并返回相应的错误信息。 |
| decr key | 将指定的 key 的 value 原子性的递减 1。 如果该 key 不存在,其初始值为 0,在 decr 之后其值为-1。 如果 value 的值不能转成整型,如 hello,该操作将执行失败并返回相应的错误信息。 |
| append key value | 如果该 key 存在,则在原有的 value 后追加该值; 如果该key不存在,则重新创建一个 key/value。 |
Redis 的列表相当于 Java 语言里面的 linkedList,是链表而不是数组 。这意味着list 的插入和删除操作非常快,时间复杂度为 O(1),但是查找数据很慢,时间复杂度为 O(n) 。
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。在插入时,如果该键并不存在,Redis 将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除 ,那么该键也将会被从数据库中删除。 List 中可以包含的最大元素数量是 4294967295。
| 命令 | 说明 |
|---|---|
| lpush key value1 value2 ... | 在指定的 key 所关联的 list 的头部插入所有的values。 如果该 key 不存在,该命令在插入的之前创建一个与该 key 关联的空链表,之后再向该链表的头部插入数据。 插入成功,返回元素的个数。 |
| rpush key value1、value2 ... | 在该 list 的尾部添加元素。 如果该key不存在则创建该key的链表,再插入数据。 |
| lrange key start end | 获取链表中从 start 到 end 的元素的值。(下标从0开始) start、end 可为负数,若为-1 则表示链表尾部的元素,-2 则表示倒数第二个,依次类推… |
| lpop key | 返回并弹出(即删除)指定的 key 关联的链表中的第一个元素,即头部元素。 |
| rpop key | 从尾部弹出(即删除)元素。 |
| llen key | 返回指定的key关联的链表中的元素的数量。 |
| lset key index value | 设置链表中的 index 的脚标的元素值,0 代表链表的头元素,-1 代表链表的尾元素。 |
Redis 的 Set 是 string 类型的无序集合(集合中不允许有重复的元素)。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
和 List 类型相比,Set 类型在功能上还存在着一个非常重要的特性,即在服务器端完成多个 Sets 之间的聚合计算操作,如 unions、intersections 和 differences。由于这些操作均在服务端完成,因此效率极高,而且也节省了大量的网络 IO 开销。
| 命令 | 说明 |
|---|---|
| sadd key value、value2 ... | 向 set 中添加数据,如果该 key 的值已有则不会重复添加 。 |
| smembers key | 获取 set 中所有的成员。 |
| scard key | 获取 set 中成员的数量。 |
| sismember key value | 判断参数中指定的成员(value)是否在该 set 中,1 表示存在,0 表示不存在或者该 key 本身就不存在。 |
| srem key member1 member2 ... | 删除 set 中指定的成员。 |
| srandmember key | 随机返回 set 中的一个成员。 |
| sdiff key1 key2 | 返回 key1 与 key2 中相差的成员,而且与 key 的顺序有关。即返回差集。 即返回key1绑定的集合中key2绑定集合中没有的元素。 |
| sdiffstore destination key1 key2 | 将 在key1中而不在key2中的元素存储在destination 上。 |
| sinter key1 key2 ... | 返回交集。 |
| sinterstore destination key1 key2 ... | 将返回的交集存储在 destination 上。(如果destination中有值的话将会被覆盖!) |
| sunion key1 key2 ... | 返回并集。 |
| sunionstore destination key1 key2 ... | 将返回的并集存储在 destination 上。 |
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。
| 命令 | 说明 |
|---|---|
| zadd key score member score2 member2 ... | 将所有成员以及该成员的分数存放到 sorted-set 中 。 |
| zcard key | 获取集合中的成员数量。 |
| zcount key min max | 获取分数在[min,max]之间的成员数量。 |
| zincrby key increment member | 设置指定成员的增加的分数。返回增加后的分数。 |
| zrange key start end[withscores] | 获取集合中脚标为 start-end 的成员,[withscores]参数表明返回的成员包含其分数。end=-1:表示最后一个成员。 例如:获取key=ccbx,中从第一个成员到第2个成员的值并且同时输出分数: zrange ccbx 0 2 withscores |
| zrangebyscore key min max [withscores] [limit offset count] | 返回分数在[min,max]的成员并按照分数从从低到高排序。 [withscores] :显示分数; [limit offset count]:offset,表示从下表为offset的元素开始并返回count个成员。 |
| zrank key member | 返回成员在集合中的位置。(从0开始) |
| zrem key member ... | 移出集合中指定的成员,可以指定多个成员。 |
| zscore key member | 返回指定成员的分数。 |
Redis hash 是一个键值(key=>value)对集合。Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。每一个Hash 可以存储 4294967295 个键值对。
| 命令 | 说明 |
|---|---|
| hset key field value | 为指定的key设定 field/value 对(键值对)。 多个属性也可以多次添加。(不太推荐) |
| hgetall key | 获取key中所有的 field-vlaue 。 |
| hget key field | 返回指定的 key 中的 field 的值。 |
| hmset key field1 value1 field2 value2 ... | 设置 key 中的多个 filed/value 。 |
| hmget key fileld1 field2 ... | 获取 key 中的多个 filed 的值。 |
| hexists key field | 判断指定的 key 对应 hash 中的 filed 是否存在。(返回1:存在。返回0:不存在) |
| hdel key field[field ...] | 删除指定 key 中一个或多个 field。(返回删除的数量) |
| hlen key | 获取 key 所包含的 field 的数量。 |
| hincrby key field increment | 设置 key 中 filed 的值增加 increment(注意数据类型)。如:age增加 20。 |
五、Spring Boot 使用Redis 5.1 引入依赖【备注】此部分后期补充。
5.2 application.yml配置redisorg.springframework.boot spring-boot-starter-data-redis org.apache.commons commons-pool2 2.7.0
# Redis 相关配置
spring:
redis:
host: 192.168.238.66 # Redis 服务器主机。
port: 6379 # Redis 服务器端口。(默认:6379)
database: 1 # 连接工厂使用的数据库索引。(默认:0)
timeout: 30000 # 读取超时。(单位:毫秒)
#可扩展的线程安全Redis客户端,用于同步、异步和反应式使用
lettuce:
pool: #Redis的池属性
max-active: 20 #连接池的最大连接数,负数表示没有限制。
max-wait: -1 #最大阻塞等待时间 (负数表示没限制)
max-idle: 6 #最大空闲连接数量(负数表示没有限制)
min-idle: 0 #最小连接数
5.3 自定义 Redis 配置类
package com.ccbx.config;
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
// 在给定对象和 Redis 存储中的底层二进制数据之间执行自动序列化/反序列化。
// 如果使用自动配置类中的RedisTemplate对象,该对象默认对key和value都采用JDK序列化器来序列化
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
// 构造一个新的RedisTemplate实例。(如果只是操作字符串,还可以用 StringRedisTemplate)
RedisTemplate template = new RedisTemplate<>();
// 设置连接工厂。
template.setConnectionFactory(factory);
// 使用Jackson2JsonRedisSerialize 替换默认的jdkSerializeable序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
//简单String到字节 [](和返回)序列化程序。
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
//Spring 的中央缓存管理器 SPI。
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间 600 秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(600))
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(redisSerializer))
.serializevaluesWith(RedisSerializationContext.SerializationPair.
fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory).cacheDefaults(config).build();
return cacheManager;
}
}
5.4 调用 RedisTemplate 的 API
首先注入上面的自定义的Bean。
@Autowired private RedisTemplate redisTemplate;
然后调用 redisTemplate 对象的相关命令,如下:
| 命令 | 说明 |
|---|---|
| redisTemplate.boundValueOps(key) | 操作 string |
| redisTemplate.boundListOps(key) | 操作 list |
| redisTemplate.boundSetOps(key) | 操作 set |
| redisTemplate.boundZSetOps(key) | 操作 ZSet |
| redisTemplate.boundHashOps(key) | 操作 Hash |
六、Spring session(session共享)【备注】如果只是操作字符串,还可以用 StringRedisTemplate。
StringRedisTemplate 和 RedisTemplate 区别:
- StringRedisTemplate 继承 RedisTemplate。
- StringRedisTemplate 默认采用的是 String 的序列化策略(StringRedisSerializer),保存的key和 value 都是采用此策略序列化保存的。
- RedisTemplate 默认采用的是 JDK 的序列化策略(JdkSerializationRedisSerializer),保存的key 和 value 都是采用此策略序列化保存的。
使用Spring Session+Redis实现session共享。
Session共享就是在分布式系统中,解决session不一致问题。当我们的应用需要两个或者两个以上的tomcat服务器来支撑时,就要考虑Session共享了。Session共享也叫Session同步或者Session一致性。
Spring为我们提供了Spring Session进行管理我们的HttpSession。Spring session 是将HttpSession存放在Redis中,这样我们session就能在多个服务器共享了。Session共享的步骤如下:
6.2 application.yml配置spring sessionorg.springframework.boot spring-boot-starter-data-redis org.apache.commons commons-pool2 2.9.0 org.springframework.session spring-session-data-redis
spring:
session:
store-type: redis #会话的存储类型( Redis 支持的会话)
# Redis 相关配置(参考上面redis的配置)
6.3 @EnableRedisHttpSession注解
@EnableRedisHttpSession注解:这个注解的主要作用是注册一个 SessionRepositoryFilter,这个 Filter 会拦截所有的请求,对 Session 进行操作,也就是开启 Session 共享功能。详细源码解析参考
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 24*60*60)
public class RedisSessionConfig {
}
| 属性 | 说明 |
|---|---|
| maxInactiveIntervalInSeconds | 设置 Session 失效时间。(单位:秒) |
| redisFlushMode | Redis 会话的刷新模式。(默认值为 ON_SAVE ) |
| cleanupCron | 过期会话清理作业的 cron 表达式。 默认情况下每分钟运行一次。 |
| redisNamespace | 为键定义唯一的命名空间。 提示:该值用于通过将前缀从默认spring:session:更改为< redisNamespace>:来隔离会话。 |
| saveMode | 会话的保存模式。 |
编写测试类:
@Controller
public class RedisSessionTestController {
//跳转到登录页面
@RequestMapping("/")
public String tologin(HttpSession session,HttpServletRequest req, Model model){
System.out.println("sessionID:"+session.getId()+"服务器端口号:"+req.getServerPort());
return "login";
}
//列表页面
@RequestMapping("tologin")
public String productlist(HttpSession session, HttpServletRequest req){
session.setAttribute("loginUser",new User("张良",22));
System.out.println("sessionID:"+session.getId()+"服务器端口号:"+req.getServerPort());
return "list";
}
}
使用图形界面查看redis中存入的相关信息:
redis存储的session相关结构信息:
- spring:session:expirations:(Set 结构):用户 ttl 过期时间记录 , 这个 key中的值是一个时间戳,根据这个 Session 过期时刻滚动至下一分钟而计算得出。这个 key 的过期时间为 Session 的最大过期时间 +5 分钟。
- spring:session:sessions:(Hash 结构):sessionAttr:Attribute名, 存储 Session 的详细信息,包括 Session 的过期时间间隔、最后的访问时间、attributes 的值。这个 key 的过期时间为 Session 的最大过期时间 +5 分钟。
- spring:session:sessions:expires:(String 结构):过期时间记录 : 这个 k-v 不存储任何有用数据,只是表示 Session 过期而设置。这个 key 在 Redis 中的过期时间即为 Session 的过期时间间隔。
Spring Session 中默认的序列化器为(JdkSerializationRedisSerializer),该序列化器效率低下,内存占用大。我们可以根据自己的需要更换其他序列化器,如 GenericJackson2JsonRedisSerializer 序列化器。部分源码解析如下:(从@EnableRedisHttpSession注解开始查看)
RedisHttpSessionConfiguration.class(部分代码)
@Configuration(proxyBeanMethods = false)
public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration
implements BeanClassLoaderAware, EmbeddedValueResolverAware, importAware {
//容器中查找注入默认的redis序列化器
@Autowired(required = false)
@Qualifier("springSessionDefaultRedisSerializer")
public void setDefaultRedisSerializer(RedisSerializer
RedisIndexedSessionRepository.class(部分代码)
public class RedisIndexedSessionRepository implements FindByIndexNameSessionRepository, MessageListener { private RedisSerializer defaultSerializer = new JdkSerializationRedisSerializer(); public void setDefaultSerializer(RedisSerializer defaultSerializer) { Assert.notNull(defaultSerializer, "defaultSerializer cannot be null"); this.defaultSerializer = defaultSerializer; } }
在配置类中创建自定义序列化器:
@Configuration
public class SpringSessionConfig {
@Bean("springSessionDefaultRedisSerializer")
public RedisSerializer setSerializer(){
return new GenericJackson2JsonRedisSerializer();
}
}
再次运行项目查看序列化效果:
5.5 Nginx负载均衡查看session共享【注意】要序列化的类必须实现 java.io.Serializable 接口(很重要!!)。未实现此接口的类将不会对其任何状态进行序列化或反序列化。
1) 将完成的项目打成 jar 包,传到服务器的目录中:/root/jars 。
2) 启动Nginx服务器;(配置如下)
# nginx负载均衡实验(不要忘记重新加载nginx服务器,使该配置生效)
upstream myTomcatServer{
# 默认使用 轮询的方式进行访问映射的tomcat服务器
server 192.168.238.66:8080;
server 192.168.238.66:8081;
#server 192.168.238.66:8082;
}
server{
listen 9005; # 设置好端口号后要通知防火墙开放该端口号,并重启防火墙
server_name www.123.com;
location / {
proxy_pass http://myTomcatServer;
}
}
3) 使用命令行运行 jar 包项目。
# 使用项目中默认的端口运行内嵌的tomcat (8080) java -jar /root/jars/redis-session.jar # 使用指定的端口号运行内嵌的tomcat(8081) java -jar jars/redis-session.jar --server.port=8081
4) 查看session共享情况。
七、Redis工具类(自定义功能)【拓展知识】Spring Session提供了3种方式存储session的方式:
- @EnableRedisHttpSession-存放在缓存redis
- @EnableMongoHttpSession-存放在Nosql的MongoDB
- @EnableJdbcHttpSession-存放在数据库



