一、概念 Redis是一款高性能的NoSQL系列的非关系型数据库 ,也叫缓存数据库,即将数据存储在缓存中,缓存的读取速度较快,能够大大提高运行效率,但是保存时间有限。NoSQL指的是Not Only SQL,不仅仅是SQL。
MySQL是SQL系列的关系型数据库 。主要用于存放持久化数据,将数据存储在硬盘中,读取速度较慢。
比较一下两种数据库
关系型数据库:MySQL、Oracle…数据之间有关联关系。比如通过外键连接两张表,存在一对多或者多对一的关系。 数据存储在硬盘文件上,读取速度较慢。 非关系型数据库:Redis、HBase…数据之间没有关联关系。以key-value这样键值对的形式存储。 数据存储在内存中,读取速度较快。 使用场景
经常使用一些不太经常发生变化的数据,操作SQL数据库是非常耗时的。我们可以用缓存思想来解决这个问题,比如Redis。
从缓存中获取数据
在实际开发中的应用场景
缓存(数据查询、短连接、新闻内容、商品内容等等) 聊天室的在线好友列表 任务队列(秒杀、抢购等等) 应用排行榜 网站访问统计 数据过期处理(可以精确到毫秒) 分布式集群架构中session的分离 二、安装 Redis官网 、Redis中文网
目前官网最新的是Redis6.0.9,但是windows编译版目前只有3.2。所以,如果想要用最新的话,需要自己编译。
编译Redis需要gcc和make,这里就用MSYS2来提供gcc和make环境。MSYS2是Windows下模拟Linux环境的工具。
首先进入清华镜像 ,下载MSYS2,后缀exe是安装版,tar.xz是免安装版。我用的安装版。安装完成之后,进入MSYS2的根目录中,找到/etc/pacman.d/下面的文件,打开,将其镜像调整为国内镜像。如,将清华镜像放到第一位即可。
打开MSYS2,执行命令,同步软件包数据
之后,下载gcc和make
去官网下载Redis的源码,解压到D盘,执行命令
用ls
命令,可以查看当前路径下的内容是不是redis源码。如果不是,可能路径没找对。
接下来,就可以进行编译。PREFIX=生成路径,如
1 make PREFIX=/d/Develop/Redis-6 .0.9
之后可能会有一堆警告,不用在意。
最后将MSYS2目录下路径为/usr/bin/msys-2.0.dll复制到已经生成的Redis的bin目录下即可。
参照Windows编译安装Redis 6.0
使用
redis.conf:配置文件 redis-cli.exe:redis的客户端 redis-server.exe:redis的服务器端。类似于mysql的服务,不安装到服务也行。 双击打开服务器端,双击客户端连接上之后,执行下面命令。
1 2 3 4 5 127.0 .0.1 :6379 > set user meethigher OK 127.0 .0.1 :6379 > get user "meethigher" 127.0 .0.1 :6379 >
三、操作 具体的使用教程,当然是看官方文档 了
3.1 Redis的数据结构 Redis存储的是key,value格式的数据,其中,key都是字符串,value有5种不同的数据结构。
value的数据类型
字符串类型,string 哈希类型,hash,可以理解为map的格式 列表类型,list,可以理解为linkedlist的格式,即双向链表,允许重复 集合类型,set,可以理解为hashset,不允许重复 有序集合类型,sortedset,不允许重复 3.2 字符串类型 添加:set key value
添加带过期时间的数据:setex key second value
获取:get key
删除:del key
3.3 哈希类型 添加:hset key field value
获取:hget key field
获取所有:hgetall key
删除:hdel key field
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 127.0 .0.1 :6379 > hset hash user meethigher(integer) 1 127.0 .0.1 :6379 > hset hash pass admin(integer) 1 127.0 .0.1 :6379 > hget hash user"meethigher" 127.0 .0.1 :6379 > hgetall hash1 ) "user" 2 ) "meethigher" 3 ) "pass" 4 ) "admin" 127.0 .0.1 :6379 > hdelall hash(error) ERR unknown command `hdelall`, with args beginning with: `hash`, 127.0 .0.1 :6379 > hdel hash pass(integer) 1 127.0 .0.1 :6379 > hgetall hash1 ) "user" 2 ) "meethigher"
3.4 列表类型 可以添加一个元素到列表的头部(左边)或者尾部(右边),允许重复元素
添加:
lpush key value:将元素加入列表左端 rpush key value:将元素加入列表右端 获取:
lrange key start end:范围获取 注意,没有rrange,如果想要start到结束,那么end处填-1。 删除:
lpop key:从列表左边删除元素,并将元素返回。 rpop key:从列表右边删除元素,并将元素返回。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 127.0 .0.1 :6379 > lpush key a(integer) 1 127.0 .0.1 :6379 > lpush key b(integer) 2 127.0 .0.1 :6379 > rpush key c(integer) 3 127.0 .0.1 :6379 > lrange key 0 -1 1 ) "b" 2 ) "a" 3 ) "c" 127.0 .0.1 :6379 > rpop key"c" 127.0 .0.1 :6379 > lrange key 0 -1 1 ) "b" 2 ) "a"
3.5 集合类型 不允许重复元素
添加:sadd key value
获取:smembers key:获取set集合中的所有元素
删除:srem key value:删除set集合中的某个元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 127.0 .0.1 :6379 > sadd key a(integer) 1 127.0 .0.1 :6379 > sadd key b(integer) 1 127.0 .0.1 :6379 > smembers key1 ) "b" 2 ) "a" 127.0 .0.1 :6379 > sadd key a b c(integer) 1 127.0 .0.1 :6379 > sadd key d e f(integer) 3 127.0 .0.1 :6379 > smemebers key(error) ERR unknown command `smemebers`, with args beginning with: `key`, 127.0 .0.1 :6379 > smembers key1 ) "c" 2 ) "d" 3 ) "a" 4 ) "f" 5 ) "e" 6 ) "b" 127.0 .0.1 :6379 > srem key d e f(integer) 3 127.0 .0.1 :6379 > smembers key1 ) "a" 2 ) "c" 3 ) "b"
3.6 有序集合类型 不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大 的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
添加:zadd key score value
获取:zrange key start end:直到结束的话,end为-1
删除:zrem key value
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 127.0 .0.1 :6379 > zadd key 60 a(integer) 1 127.0 .0.1 :6379 > zadd key 70 b(integer) 1 127.0 .0.1 :6379 > zadd key 60 c(integer) 1 127.0 .0.1 :6379 > zrange key 0 -1 1 ) "a" 2 ) "c" 3 ) "b" 127.0 .0.1 :6379 > zrange key 0 -1 withscores1 ) "a" 2 ) "60" 3 ) "c" 4 ) "60" 5 ) "b" 6 ) "70" 127.0 .0.1 :6379 > zrem key a b c(integer) 3
像一些临时的排行榜,比如热搜之类的,就是利用有序集合这种原理实现的。
3.7 通用命令 查询所有的键,*处本身就是正则:keys *
获取一个键对应的value类型:type key
删除指定的key-value:del key
1 2 3 4 5 6 7 8 9 10 11 12 13 127.0 .0.1 :6379 > keys *1 ) "user" 2 ) "hash" 127.0 .0.1 :6379 > type userstring 127.0 .0.1 :6379 > type hashhash 127.0 .0.1 :6379 > del user key(integer) 1 127.0 .0.1 :6379 > del user hash(integer) 1 127.0 .0.1 :6379 > keys *(empty array)
四、持久化 Redis是一个内存数据库,当服务器重启或者电脑重启,数据会丢失。我们可以将Redis内存中的数据,持久化保存到硬盘的文件中。
Redis持久化机制
RDB:默认方式,不需要配置,默认使用这种机制。在一定的时间中,检测key的变化,然后持久化数据。 AOF:日志记录的方式,可以记录每一条命令的操作。每一次命令操作后,来持久化数据。对性能影响较大。 4.1 RDB 编辑redis.conf配置文件
save 900 1:900秒之后,约为15分钟,有1处改变,就执行持久化
save 300 10:300秒之后,约为5分钟,有10处改变,就执行持久化
save 60 10000:60秒之后,约为1分钟,有10000处改变,就执行持久化
重新启动redis服务器,Cmd指定配置文件名称,如
1 redis-server .exe redis.conf
4.2 AOF 编辑redis.conf配置文件
appendonly no:关闭aof,默认
appendonly yes:打开aof
appendfsync always:每一次操作都进行持久化,默认关闭
appendfsync everysec:每隔一秒进行一次持久化,默认
appendfsync no:不持久化,默认关闭
同样跟RDB一样,Cmd指定配置文件运行
五、Java操作Redis Jedis:一款java操作redis数据库的工具
使用步骤:
下载jedis的jar包 使用 5.1 快速入门 步骤
获取连接 操作 关闭连接 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import org.junit.jupiter.api.Test;import redis.clients.jedis.Jedis;public class RedisTest { @Test public void test1 () { Jedis jedis = new Jedis("127.0.0.1" ,6379 ); jedis.set("love" ,"meethigher" ); jedis.close(); } }
5.2 Jedis操作Redis数据结构 Jedis操作数据结构的方法名,正好对应Redis的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 public class RedisTest { @Test public void test2 () { Jedis jedis = new Jedis(); String user = jedis.get("user" ); System.out.println(user); jedis.setex("activecode" ,20 ,"1234" ); jedis.close(); } @Test public void test3 () { Jedis jedis = new Jedis(); jedis.hset("person" ,"name" ,"meethigher" ); jedis.hset("person" ,"age" ,"3" ); jedis.hset("person" ,"gender" ,"male" ); System.out.println(jedis.hget("person" ,"gender" )); Map<String, String> person = jedis.hgetAll("person" ); Set<Map.Entry<String, String>> entries = person.entrySet(); for (Map.Entry<String,String> e:entries){ System.out.println(e.getKey()+":" +e.getValue()); } jedis.close(); } @Test public void test4 () { Jedis jedis = new Jedis(); jedis.lpush("list" ,"b" ,"a" ); jedis.rpush("list" ,"c" ); List<String> list = jedis.lrange("list" , 0 , -1 ); System.out.println(list); while (jedis.lpop("list" )!=null ){ } jedis.close(); } @Test public void test5 () { Jedis jedis = new Jedis(); jedis.sadd("set" ,"java" ,"php" ,"python" ); Set<String> set = jedis.smembers("set" ); System.out.println(set); jedis.close(); } @Test public void test6 () { Jedis jedis = new Jedis(); jedis.zadd("sorted" ,3 ,"胡列娜" ); jedis.zadd("sorted" ,2 ,"小舞" ); jedis.zadd("sorted" ,1 ,"江厌离" ); Set<String> sorted = jedis.zrange("sorted" , 0 , -1 ); System.out.println(sorted); jedis.close(); } }
5.3 Jedis连接池 使用
创建配置对象
创建JedisPool连接池对象
调用getResource()获取Jedis连接
使用
归还连接池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Test public void test7 () { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(50 ); config.setMaxIdle(50 ); JedisPool jedisPool = new JedisPool(); Jedis jedis = jedisPool.getResource(); jedis.set("user" ,"aaa" ); System.out.println(jedis.get("user" )); jedis.close(); }
创建连接池工具类
JedisUtils
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class JedisUtils { private static JedisPool pool; static { InputStream is = JedisUtils.class.getClassLoader().getResourceAsStream("jedis.properties"); Properties pro = new Properties(); try { pro.load(is); } catch (IOException e) { e.printStackTrace(); } JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal" ))); config.setMaxTotal(Integer.parseInt(pro.getProperty("maxIdle" ))); pool = new JedisPool(config, pro.getProperty("host" ), Integer.parseInt(pro.getProperty("port" ))); } public static Jedis getJedis () { return pool.getResource(); } }
5.4 案例 实现一个异步获取省市信息,然后动态渲染到页面上。
初步实现的结构,如图。
所有的功能都能正常实现,但是每次访问都需要去数据库请求数据,这就很低效。所以,可以通过缓存来优化。
具体的源码,放到gitee 上了
注意:
使用redis缓存一些不经常发生变化的数据。
数据库的数据一旦发生改变,则需要更新缓存。
数据库的表执行增删改的相关操作,需要清空redis缓存数据,重新存入。
在service对应的增删改方法中,将redis数据删除。