01-Redis数据库基础

1. NoSql数据库

1.1 Nosql数据库概述

Not Only Sql,不仅仅是SQL,指的事非关系型数据库。NoSQL不依赖业务逻辑方式存储,而是以简单的key-value模式存储。

  • 不遵循SQL标准
  • 不支持ACID四个特性
  • 远超于SQL的性能
1.2 NoSql应用场景
  • 适用场景
    • 对数据高并发的读写
    • 海量数据的读写
    • 对数据高可扩展性
  • 不适用场景
    • 需要事务支持
    • 基于sql的结构化查询存储,处理复杂的关系

1.3 常用Nosql数据库

  1. Memcache
    数据在内存中存储;一般不支持持久化;支持简单的k-v模式,支持的类型单一,只支持String类型,一般用作缓存数据库辅助持久化的数据库
  2. Redis
    数据都在内存中存储,支持持久化,主要用作备份恢复;除了支持k-v模式,还支持多种数据结构,比如list,set,hash,zset等等;一般用作缓存数据库辅助持久化的数据库
  3. MongoDB
    高性能、开源、模式自由的文档型数据库(类似于JSON);数据都在内存中,如果内存不足,会把不常用的数据保存到硬盘中;k-v模式,但是对value提供了丰富的查询功能;支持二进制数据以及大型对象的存储;可以根据数据的特点代替 RDBMS,成为独立的数据库;或者配合RDBMS,存储特定的数据。

1.4 行列式数据库

行式数据库
在这里插入图片描述

列式数据库
在这里插入图片描述
Hbase
Hbase是Hadoop项目中的数据库,用于需要对大量的数据进行随机、实时读写操作的场景中。

在这里插入图片描述

2.Redis概述与安装

2.1Redis数据库概述

  • Redis是一个开源的k-v存储系统
  • 和Memcached类似,支持存储的value类型更多,包括String,list,set,zset(sortedset),hash
  • 数据类型都支持 push/pop、add/remove及取交集、并集和茶几以及更丰富的操作,操作都是原子性
  • Redis支持各种不同方式的排序
  • 与memcached一样,为了保证效率,数据都是缓存在内存中
  • 区别在于Redis会周期性把更新的数据写入磁盘护着把修改操作写入追加的记录文件
  • Redis还实现了master-slave(主从)同步

2.2 Redis安装

  • 安装gcc
    gcc --version # 查看gcc是否安装
    yum install gcc	# 安装gcc
    
  • 解压安装redis
    tar -zxvf redis-xxxx.tar.gz  	# 先解压
    cd redis-xxx					# 进入解压后的目录
    make							# 在解压后的目录下执行,这里只是编译环境
    # 如果make报错执行
    make distclean
    
    make install					# 编译完后安装
    /usr/local/bin					# 默认的安装路径
    
  • redis目录下的文件夹
    • redis-benchmark:性能测试工具,可以在自己的机器运行,查看性能
    • redis-check-aof: 修复有问题的AOF文件
    • redi-check-dump:修复有问题的dump.rdb文件
    • redis-sentinel: Redis集群使用
    • redis-server: Redis服务器启动命令
    • redis-cli: 客户端,操作入口

2.3 Redis启动

推荐使用后台启动
  1. 备份redis.conf到其他目录 cp /opt/redis-xxx/redis.conf /etc/redis.conf (也可以自己设置复制的路径)
  2. 后台启动设置 daemonize no 给为yes(在redis.conf中128行附近)
  3. 启动命令
    vim redis.conf 
    cd /usr/local/bin
    redis-server /etc/redis.conf 
    ps -ef | grep redis
    	root     29306 29281  0 11:33 pts/2    00:00:00 vi redis.conf
    	root     29490     1  0 12:28 ?        00:00:00 redis-server 127.0.0.1:6379
    	root     29496 29436  0 12:28 pts/3    00:00:00 grep --color=auto redis
    redis-cli 
    	127.0.0.1:6379> ping
    	PONG
    	127.0.0.1:6379> 
    
  4. 关闭redis服务
    1. 在 redis-cli命令行中 输入shutdown
    2. 通过进程号关闭 ps -ef|grep redis
      kill -9 PID

2.4 Redis相关

Redis默认16个数据库,从下表0到下表15。使用select 来切换,例如:select 8。而且所有库的密码都是相同的。

  • dbsize查看当前数据库key的数量

  • flushdb 清空当前库

  • flushall 通杀全部库

  • Redis是单线程+多路IO复用技术

    • 多路复用:使用一个线程来检查多个文件描述(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程池执行。

买票的例子:1,2,3要买票(请求-火车站-数据库),通过中介黄牛来进行买票的话,黄牛在买票过程中(请求数据库),1,2,3可以做自己的事情,直达黄牛把票买好 (获取到要请求的数据)

在这里插入图片描述

2.5Redis设置数据库密码

修改redis.conf 文件中的 # requirepass foobared, 去掉注释后修改为 foobared为自己要修改的密码

在数据库命令行中 ,输入auth 密码 进行验证

	root@iZm5efvyf8qms25at28ejnZ:/usr/local/bin# redis-cli 
	127.0.0.1:6379> get k1
	(error) NOAUTH Authentication required.
	127.0.0.1:6379> auth zbdx221221
	OK
	127.0.0.1:6379> get k1
	"k1_value"
	127.0.0.1:6379> 

3. Redis五大常用数据类型

3.1 Redis中的 key

在 /usr/local/bin目录下输入 redis-cli 进入Redis数据库命令行

  • key的操作

    • keys * : 查看当前库的所有key
    • exits key : 判断某个key是否存在
    • type key : 判断key是什么类型
    • del key : 直接删除指定的key
    • unlink key : 根据value选择非阻塞的删除,只是把key从keyspace元数据中删除,真正的删除是在后续异步操作。
    • expire key 10 : 设置key的过期时间为10秒
    • ttl key : 查看key的剩余的过期时间 (-1表示 永不过期, -2表示已经过期)
  • 其他操作

    • select num : num=(0-15)切换数据库
    • dbsize : 查看当前库的key的数量
    • flushdb : 清空当前数据库
    • flushall : 通杀全部库

3.2 String类型数据

3.2.1 简介

  • String是Redis中最基本的数据类型,一个key对应一个value。
  • 在Redis中String类型是 二进制安全的,就是String可以包含任何数据,比如jpg图片、视频或者序列化对象等等。
  • String是Redis最基本的数据类型,一个Redis中字符串value最多可以是512M。

3.2.2 常用命令

设置 k-v值

set key value
get key
append key value # 追加值到原来的value后
strlen key # 获取长度
setnx key value # 只有key不存在才能设置成功

对数据进行增减

incr key # key中存储的数字值+1,只能对数字进行操作,如果为空新增值为1
decr key # key中存储数字-1
incrby/decrby key 步长 # 自定义key中 数字增大减少的值
Redis中增加或者减少的操作是原子性的,不会被线程调度机制打断,因为Redis是单线程操作

对多个key进行赋值和取值

mset k1 v1 k2 v2 k3 v3 # 对多个值进行设置
mget k1 k2 k3 # 获取多个key
msetnx k1 v1 k2 v2 k3 v3 # 当所有key都不存在才会添加成功

getrange key start end
setranget key index value # 从index位置开始,后面的值都会被覆盖

setex key time value # 设置key的时候设置过期时间
getset key newValue # 获取旧值 ,设置新值

3.2.3 String类型的数据结构

Redis中String的数据结构是简单的动态字符串(Simple Dynamic String,缩写SDS),内部 结构和Java的ArrayList类似,采用预分配冗余空间的方式减少内存的频繁分配。当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容时一次只会多扩1M。字符串最大长度为512M。

3.3 List列表

3.3.1常用命令

Redis中列表是一个双向列表的数据结构,

lpush/rpush key value1, value2, value3… # 从左/右加入值
lpop/rpop key # 从左边或者右边弹出一个值。 键在值在,值取完键也不存在了

rpop|lpush key1 key2 # 从key1中右侧弹出值,放入key2的左侧

lrange key start end # 从左侧开始获取元素,start0,end -1则表示获取所有
index key num # 获取从左到右第num个元素
llen key # 获取列表长度

linsert key before/after old_value new_value # 在列表中指定值前/后添加值
lrem key n value # 从左侧开始删除 n 个value值
lset key index value # 将列表中key下标为index的值替换为value

3.3.2 数据结构

List的数据结构为快速链表 quickList

  • 如果列表中数据很少,会分配一块连续的内存存储,这个结构是ziplist,就是压缩列表
  • 当数据比较多的时候就会采用 quicklist,就是多个ziplist,使用双向指针穿起来

3.3 Set数据

Set是String类型的无序集合,底层是一个Hash表,因此 增删改查数据的时间复杂度都是 O(1)

3.3.1 常用命令

sadd key val1 val2 val3 … # 添加一个或者多个元素
smember key # 获取集合中的所有值
sismember key val1 # 判断集合中是否有 val1, 有返回1,否则返回0

scard key # 获取集合中元素的个数
srem key val1, val2… # 删除集合中的元素
spop key # 随机从set中弹出一个值
srandmember key n # 随机取出n个值,不是弹出

smove key1 value key2 # 将key1中的值value移动到key2中
sinter key1 key2 # 返回两个集合的交集元素
sunion key1 key2 # 返回两个集合中的并集元素
sdiff key1 key2 # 返回两个集合中的差集(key1中有, key2中没有)

3.3.2 数据结构

Set数据结构是dict字典,字典是用hash表实现的

3.4 Hash数据类型

Redis中hash是一个String类型的field和value的映射表,hash特别适合用于存储对象,类似于Java里面的Map<String, Object>

3.4.1常用命令

hset key field value # 给key集合中的field赋值value
hget key field value # 从key集合中取出value
hmset k1 v1 k2 v2 … # 批量设置hash的值
hexists key field # 查看哈希表key中是否存在 field
hkeys key # 列出该hash集合的所有field
hvals key # 列出该hash集合的所有value
hincrby key field increment # 给hash中field的值添加增量 increment
hsetnx key field value # 将哈希表key中的field的值设置为value,field不存在才会成功

3.4.2数据结构

Hash类型对应的数据结构有两种:ziplist(压缩列表) , hashtable(哈希表)。 当field-value长度短且个数少的时候,使用ziplist,否则使用hashtable。

3.5 Redis有序集合ZSet

zset是Redis中没有重复元素的字符串集合。有序集合的每个成员都关联了一个评分score,用来对元素进行排序。

3.5.1 基础命令

	zadd key score1 value1 score2 value2...  	# 添加评分和值到zset中
	zrange topn start end [withscores]			# start 0 end -1就是 所有元素, 可选参数withscores带分数返回
	zrangebyscore key min max [withscores] [limit offset count]	# 返回有序集合key中所有score值介于min和max之间的成员(从小到大)
	zrevrangebyscore key max min [withscores] [limit offset count]	# 改为从大到小排序
	
	zincrby key increment value 			# 给元素添加增量increment
	zrem key value							# 删除key下的指定元素
	zcount key min max						# 统计集合中 min 和 max之间的元素
	zrank key value 						# 返回该值再集合中的排名,从0开始
	zrange topn start end [withscores]		# 获取start到end排名之间的元素

3.5.2 数据结构

SortedSet(zset)是Redis提供的一个非常特别的数据结构,一方面等价于Java的数据结构Map<String, Double>, 可以给每个元素value赋予一个权重score;另一方面类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次。

  • zset底层使用两种数据结构
    • hash:作用就是关联元素 vale和权重score,保障元素value的唯一性。可以通过元素value找到对应的score
    • 跳跃表:给元素value排序,根据score的范围获取元素列表

3.5.3 跳跃表

有序集合的底层实现可以用 数组、平衡树、链表等等。数组元素的插入和删除不方便;平衡时和红黑树效率高但是结构复杂;链表查询的效率比较低。跳跃表效率堪比红黑树,但是实现比红黑树简单。
在这里插入图片描述

4. Redis配置文件

redis.conf文件中, Redis是按照字节byte进行存储的

bind 127.0.0.1 -::1     	# 绑定本地只能本地访问, 加# 注释掉后就可以随便访问

protected-mode yes			# 开启保护模式,只能本地访问。 改为no就可以远程访问

port 6379					# 端口

tcp-backlog 511				# 表示正在进行三次握手和已经完成三次握手的连接的最大数

timeoout  0					# 0表示永不超时,单位是秒

tcp-keepalive 300			# 每隔300秒检测tcp是否还在连接

daemonize yes				# 改为yes就可以后台启动

pidfile	/var/run/redis_ 6379.pid					# 存放每次redis的进程号的文件

loglevel notice				# 日志的级别(debug, verbose, notice默认级别, warning)

logfile ""					# 日志路径设置

databases 16				# Redis默认16个数据库,默认使用的是第0个

requirepass xxx				# 设置Redis密码

maxclients	100000			# 最大的连接数量

5. Redis的发布和订阅

5.1 什么是发布和订阅

Redis的发布和订阅(pub/sub)是一种消息通信模式。Redis客户端可以订阅任意数量的频道。
在这里插入图片描述

5.2 Redis命令实现发布和订阅

  1. 打开一个客户端订阅 channel1
    127.0.0.1:6379> subscribe channel1
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "channel1"
    3) (integer) 1
    
  2. 打开另外一个客户端,给channel1发布消息
    127.0.0.1:6379> PUBLISH channel1 "nihao"
    (integer) 1
    127.0.0.1:6379> 
    
  3. 打开第一个客户端就可以看到发送的消息
    127.0.0.1:6379> subscribe channel1
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "channel1"
    3) (integer) 1
    1) "message"
    2) "channel1"
    3) "nihao"
    

6. Redis的新型数据类型

6.1Bitmaps

6.1.1 简介

  1. 简介
  • 计算机使用二进制作为信息的基础单位,1个字节等于8位。
  • Redis提供的Bitmaps这个数据类型可以实现对位的操作:
    • Bitmaps本身不是一种数据类型,实际上就是一种字符串(key-value),但是可以对字符串的位进行操作
    • Bitmaps单独提供一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同。可以把Bitmaps看作是一个以位数位单位的数组,每个单元只能存储0或者1,数组的下标在Bitmaps中被叫做偏移量
  1. 实例
    将每个独立的用户是否访问过网站存放在Bitmaps中,将访问过的用户记作1,没有访问过的用户记作0,偏移量作为用户的id
    在这里插入图片描述

6.1.2 Bitmaps案例

  • bitmap插入值、获取值、获取为1的值,对两个bitmap进行操作
	# setbit key index value   设置值
	127.0.0.1:6379> setbit users:20210101 1 1
	(integer) 0
	127.0.0.1:6379> setbit users:20210101 6 1
	(integer) 0
	127.0.0.1:6379> setbit users:20210101 15 1
	(integer) 0
	127.0.0.1:6379> setbit users:20210101 19 1
	(integer) 0
	
	# getbit key index		获取值
	127.0.0.1:6379> getbit users:20210101 1
	(integer) 1
	
	# 统计值为1的 数量
	127.0.0.1:6379> bitcount users:20210101 
	(integer) 4
	127.0.0.1:6379> bitcount users:20210101 1 10
	(integer) 2 
	
	# 添加新的数据
	127.0.0.1:6379> setbit users:20220101 1 1
	(integer) 0
	127.0.0.1:6379> setbit users:20220101 3 1
	(integer) 0
	127.0.0.1:6379> setbit users:20220101 15 1
	(integer) 0
	127.0.0.1:6379> setbit users:20220101 20 1

	# 获取两天都访问过的用户的总数
	20210101访问的用户   1 6 15 19
	20220101访问的用户   1 3 15 20
	127.0.0.1:6379> bitop and users:2021_220101 users:20210101 users:20220101
	
	127.0.0.1:6379> bitcount users:2021_220101
	(integer) 2
  1. Bitmaps 和 set对比
    • 如果用户活跃用户量达到了百千万级别以上,那么使用bitmaps会很大程度上节省内存空间
    • 如果用户活跃量只有十几万,那么使用set更加合理

6.2 HyperLogLog

6.2.1 简介

  • 统计页面的访问量PV(Page View),我们可以使用Redis的 incr,incrby实现
  • 但是像UV(UniqueVisitor 独立访客)、独立IP数量、搜索记录等去重和计数的问题,应该怎么解决?
    • 数据存储在mysql,使用distinct count计算不重复的个数
    • 使用Redis提供的hash、set、bitmaps等数据结构来处理
  • 但是数据量很大的时候,这两种方法就没有 HyperLogLog更加有效地利用内存以及空间
    • HyperLogLog在输入元素的数量或者体积非常大的时候,计算基数(不重复元素的个数)所需要的空间是固定的,而且是很小的。
    • HyperLogLog只需要12k的内存,就可以计算接近2^64个不同元素的基数
  • HyperLogLog不能返回输入的各个元素,只能计算出输入元素的基数,而不会存储元素本身。

6.2.2 命令

# pfadd Hname val1 val2 val3
127.0.0.1:6379> pfadd hll1 "redis" "java" "C++"
(integer) 1
127.0.0.1:6379> pfadd hll1 "java" "Java"
(integer) 1

# pfcount Hname
127.0.0.1:6379> pfcount hll1
(integer) 4 

# pfmerge newName Hname1 Hname2  合并两个HyperLogLog
127.0.0.1:6379> pfadd hll2 "C#" "python"
(integer) 1
127.0.0.1:6379> pfmerge hll hll1 hll2
OK
127.0.0.1:6379> pfcount hll
(integer) 6

6.3 Geospatial

6.3.1简介

Redis增加了对GEO类型 (地理位置坐标信息) 的支持。Redis基于该类型,提供了经纬度设置、查询、范围查询、距离查询、经纬度Hash等常见的操作。

6.3.2 命令

两极的坐标无法直接添加无效的经度从-180度到180度。有效的纬度从 -85.05112878度到85.05112878。超出这个值就会返回一个错误。

  • 添加经纬度

    # geoadd name lon lat field
    127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
    (integer) 1
    127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing
    (integer) 3
    
  • 获取经纬度,两点之间的距离

    # geopos name field
    127.0.0.1:6379> geopos china:city beijing
    1) 1) "116.38000041246414185"
       2) "39.90000009167092543"
    
    # geodist name field1 field2    两点之间的距离,单位可以选择 m km ft mi
    127.0.0.1:6379> geodist china:city beijing  shanghai km
    "1068.1535"
    
    # georadius name lon lat value unit  取数据集合name中以lon,lat为中心,半径为value单位是unit的范围内的城市
    127.0.0.1:6379> georadius china:city 110 30 1000 km
    1) "chongqing"
    2) "shenzhen"
    

7.Jedis操作Redis6

  1. 创建新的maven工程,什么都不需要导入
  2. 导入依赖
       <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.3.0</version>
        </dependency>
    
  3. 测试连接
    public class JedisDemo1 {
        public static void main(String[] args) {
    
            /*服务器需要配置的点 redis.conf
            * bind 127.0.0.1        需要注释掉
            * protected-mode no     由yes修改为no
            * 修改完之后需要重启redis(1.在redis命令行中shutdown; 2.查找pid进程号并kill)
            * */
    
            // 创建一个Jedis对象, 参数  hots和port
            Jedis jedis = new Jedis("xxxxxx", 6379);   // 这里xxx为自己的服务器ip
            jedis.auth("xxxxxx");						// 这里xxx是自己设置的redis密码,如果没有设置就不用写
    
            // 测试
            String value = jedis.ping();
            System.out.println(value);					// 连接成功会输出PONG
        }
    }
    
    1. 连接失败
      如果连接失败查看是否自己的ip与端口是否正确
      确定配置文件redis中 bind 和 protected-mode是否配置正确
      确定防火墙是否开启 systemctl status firewall; systemctl stop firewall;
      确定端口号是否开放,在阿里云安全组配置

    2. Java操作数据的几种方法

    
    // 1.操作key的方法
    @Test
    public void demo01(){
        Jedis jedis = new Jedis("xxxxx", 6379);
        jedis.auth("xxxxx");
    
        // 添加key
        jedis.set("name", "lucy");
    
        Set<String> keys = jedis.keys("*");     // 获取所有的key
        for (String key : keys) {
            System.out.println(key);
        }
    
        // 添加多个k-v
        jedis.mset("k1", "v1", "k2", "v2", "k3", "v3");
        List<String> mget = jedis.mget("k1", "k2");
        for (String s : mget) {
            System.out.println(s);
        }
        jedis.close();
    }
    
    
    // 2.操作List
    @Test
    public void demo02(){
        Jedis jedis = new Jedis("xxxxx", 6379);
        jedis.auth("xxxxx");
    
        jedis.lpush("key1", "Java", "Php", "Python");
        List<String> values = jedis.lrange("key1", 0,-1);
        for (String value : values) {
            System.out.println(value);
        }
    }
    
    // 3.操作Set
    @Test
    public void demo03(){
        Jedis jedis = new Jedis("xxxxx", 6379);
        jedis.auth("xxxxx");
    
        jedis.sadd("names", "lucy", "jack");
    
        Set<String> names = jedis.smembers("names");
        System.out.println(names);
    	jedis.close();
    }
    
    
    // 4.操作hash
    @Test
    public void demo04(){
        Jedis jedis = new Jedis("xxxxx", 6379);
        jedis.auth("xxxxx");
    
        jedis.hset("users", "age", "20");
        jedis.hset("users", "name", "黑蛋");
    
        String name = jedis.hget("users", "name");
        String age = jedis.hget("users", "age");
        System.out.println(name + " : " + age);
        jedis.close();
    }
    
    
    
    // 4.操作zset
    @Test
    public void demo05(){
        Jedis jedis = new Jedis("xxxxx", 6379);
        jedis.auth("xxxxx");
    
        jedis.zadd("china", 101d, "shanxi");
        jedis.zadd("china", 100d, "beijing");
        jedis.zadd("china", 103d, "shanghai");
        jedis.zadd("china", 102d, "shenzhen");
    
        Set<String> china = jedis.zrange("china", 0, -1);
        System.out.println(china);
        jedis.close();
    }
    

8. 模拟验证码发送

  • 功能要求

    • 输入手机号,点击发送后随机生成6位数字码,2分钟有效
    • 输入验证码进行验证
    • 每个手机号每天只能输入3次
  • 实现思路

    • Random随机生成6位数字验证码
    • 验证码2分钟有效:将验证码放入redis,设置过期时间120m
    • 判断验证是否一致:从redis获取并对比
    • 每天只能发送3次:incr每次发送后+1,大于2后就提示不能发送
public class PhoneCode {


    public static void main(String[] args){
        String phoneNum = "xxxxxxxxxxxxx";

        boolean flag = verifyCode(phoneNum);

        // 如果获取验证码的次数没有用完
        if(flag){
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入验证码(按回车接受输入):");
            String code = scanner.nextLine();

            verifyRedisCode(phoneNum, code);
        }

    }


    // 1.生成六位数字验证码
    public static String getRandomCode(){
        Random random = new Random();
        String code = "";

        for(int i=0; i<6; i++){
            int rand = random.nextInt(10);
            code += rand;
        }

        return code;
    }

    // 2. 每个手机每天只能发送三次,验证码放入到redis中,设置过期时间
    public static boolean  verifyCode(String phone){
        //  验证码和手机发送次数的限制条件不一样,因此把手机和验证码存到不同的key中

        // 连接redis
        Jedis jedis = new Jedis("xxxxxxxxxx", 6379);
        jedis.auth("xxxxxxxxxxxxxxxxx");

        // 拼接key,手机发送的次数
        String countKey = "VerifyCode-" + phone + "-count";
        String codeKey  = "VerifyCode-" + phone + "-code";

        // 判断手机发送的次数
        String count = jedis.get(countKey);
        if(count == null){
            // 没有发送次数,第一次发送
            jedis.setex(countKey, 24*60*60, "1");   // 设置过期时间为1天
        }else if(Integer.parseInt(count) <= 2){
            jedis.incr(countKey);
        }else if(Integer.parseInt(count) > 2){
            System.out.println("今天的发送次数已经用完(三次)");
            jedis.close();

            return false;
        }

        // 验证码存入数据库,并且设置过期时间
        String vCode = getRandomCode();
        System.out.println("提示:" + vCode);
        jedis.setex(codeKey, 120,  vCode);
        jedis.close();

        return true;
    }

    // 3.验证码的校验
    public static void verifyRedisCode(String phone, String code){
        Jedis jedis = new Jedis("xxxxxxxxxx", 6379);
        jedis.auth("xxxxxx");

        String codeKey = "VerifyCode-" + phone + "-code";
        String redisCode = jedis.get(codeKey);

        if(redisCode.equals(code)){
            System.out.println("验证成功");
        }else{
            System.out.println("验证失败");
        }
    }
}

9.SpringBoot整合Redis

  1. SpringBoot整合Redis需要两个依赖

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
    	
    		<!--SpringBoot整合Redis2.x还需要导入依赖 common-pool2-->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
                <version>2.6.0</version>
            </dependency>
    
  2. SpringBoot application.yml配置redis

    spring:
      redis:
        host: xxxxx
        port: 6379
        database: 0             # 使用的database索引
        timeout: 1800000        # 单位毫秒
        lettuce:
          pool:
            max-active: 20      # 连接池的最大限制,-1代表没有限制
            max-wait: -1        # 最大阻塞等待时间  -1表示没有限制
            max-idle: 5         # 最大空闲连接
            min-idle: 0         # 最小空闲连接
        password: xxxxxxx
    
    1. 配置Redis redisConfig
    @EnableCaching          // 开启缓存
    @Configuration
    public class RedisConfig extends CachingConfigurerSupport {
        @Bean
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            RedisSerializer<String> 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);
            template.setConnectionFactory(factory);
    //key序列化方式
            template.setKeySerializer(redisSerializer);
    //value序列化
            template.setValueSerializer(jackson2JsonRedisSerializer);
    //value hashmap序列化
            template.setHashValueSerializer(jackson2JsonRedisSerializer);
            return template;
        }
    
        @Bean
        public CacheManager cacheManager(RedisConnectionFactory factory) {
            RedisSerializer<String> 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;
        }
    }
    
    
    1. 书写Controlle测试
    @Controller
    public class RedisController {
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        @GetMapping("/redis")
        @ResponseBody
        public String testRedis(){
            redisTemplate.opsForValue().set("name", "lucy");
            String name = (String) redisTemplate.opsForValue().get("name");
            return name;
        }
    
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值