一、学习Redis基础

  1. 在前面学习了MySQL数据库,它是一种传统的关系型数据库,我们可以使用MySQL来更好地管理和组织我们的数据,虽然在小型Web下,只需要一个MySQL+Mybatis自带的缓存系统就可以胜任大部分的数据存储工作,但是MySQL的缺点也很明显,他的数据始终是存储在硬盘上,对于我们的用户信息这种不需要经常发生修改的内容,使用MySQL确实可以,但是如果是快速更新或是频繁使用的数据,比如微博resource、双十一秒杀,这些数据不仅要求服务器需要提供更高的响应速度,而且还需要面对短时间内上百万甚至上千万次访问,而MySQL的磁盘IO读写性能完全不能满足上面的需求,能够满足上述需求的只有内存,因为速度远高于磁盘IO。

  2. NoSQL概论
    NoSQL全称是Not Only SQL(不仅仅是SQL) 它是一种非关系型数据库,相比传统SQL关系型数据库,它:

  • 特点:

    1. 不保证关系数据的ACID特性
    2. 并不遵循SQL标准
    3. 消除数据之间关联性
  • 优势:

  1. 远超传统关系型数据库的性能

  2. 非常易于扩展

  3. 数据模型更加灵活

  4. 高可用

    这样,NoSQL的优势就出来了,这就是我们正在寻找的高并发海量数据的解决方案。

  5. NoSQL数据库分为以下几种:

  • 键值存储数据库:所有的数据都是以键值方式存储的,类似于HashMap,使用起来非常简单方便,性能也非常高

  • 列存储数据库:这部分数据库通常用来应对分布式存储的海量数据。键仍然存在,但是他们的特点是指向了多个列

  • 文档型数据库:它是以一种特定的文档格式存储数据,比如JSON格式,在处理网页等复杂数据时,文档型数据库比传统型键值数据库查询效率更高

  • 图形数据库:利用类似于图的数据结构存储数据,结合图相关算法实现高速访问

Redis是一个开源的键值存储数据库,所有的数据全部存在内存中,它的性能远远高于磁盘IO,并且它也可以支持数据持久化,它还支持横向扩展、主从复制等。

  1. Redis中键值对命令

set ye 44
get ye

定义数据有效时间
reprie a 10

  1. HashMap键值对
    hset yecode 111
    hset b name lbw age 10
    hget b
    hexists <key> <字段> #判断某个字段是否存在
    hdel <key> <字段> #删除某个字段
    hdel <key> #删除hash中某个键

我们现在想要知道Hash中一共存了多少个键值对:hlen <key>

我们也可以一次性获取所有字段的值: hvals <key>

  1. List
    我们可以直接向一个已存在或是不存在的List中添加数据,如果不存在,会自动创建:
    #向列表头部添加元素
    lpush
    #向列表尾部添加元素
    rpush
    #在指定元素前面/后面插入元素
    linsert before/after <指定元素>
    1
    2
    lpush c 111 222 333
    insert c before 222 000
    同样的获取元素也非常简单
    #根据下表获取元素
    lindex <下标>
    #获取并移除头部元素
    lpop
    #获取并移除尾部与阿奴苏
    rpop
    #获取指定范围内的
    lrange start stop

二、持久化

  • Redis数据库中的数据是存放在内存中的,虽然很高效,但是这样存在一个非常严重的问题,如果突然停电,或者突然关闭了终端,那数据不就全部丢失了吗?

  • 这个时候就需要持久化,我们需要将我们的数据备份到硬盘上,防止断电或机器故障导致数据丢失

  1. 持久化实现方法有两种方案:
  • 一种是直接保存当前已经存储的数据,相当于复制内存中的数据到硬盘上,需要回复数据时直接读取即可
  • 一种是保存我们存放数据的所有过程,需要恢复数据时,只需要将整个过程完整地重演一篇就能保证与之前数据库中的内容一致。

1. RDB

RDB就是上述的第一种方案,保存到本地,使用以下命令

1
2
3
4
save
--注意上面这个命令会直接保存,会占用一定时间,可以单独开一个子进程后台执行保存
bgsave
--可以单独开一个子进程后台执行保存

执行后,会在服务端目录下生成一个dump.rdb文件,而这个文件中就保存了内存中存放的数据,当服务器重启后,会自动加载里面的内容到对应数据库中。
保存后我们就可以关闭服务器
shutdown

2. AOF

虽然RDB能够很好地解决持久化问题,但是它的缺点也很明显:每次都需要去完整地保存整个数据库中的数据,同时后台保存过程中也会产生额外的内存开销,最严重的是它不是实时保存的,如果在自动保存出发之前服务器崩溃,那么依然会导致少量数据的丢失
AOF就是另一种方式,它会以日志的形式将我们每次执行的命令都进行保存,服务器重启时会将所有命令依次执行,通过重演的方式将数据恢复,这样就能很好解决实时性存储问题。

但是,我们多久写一次日志呢?我们可以自己配置保存策略
always:每次执行写操作都会保存一次
everysec:每秒保存一次(默认配置)
no: 看系统心情

开启AOF自动记录日志功能需要在日志文件中找到oppendonly,将no改成yes

重启服务器后,可以看到服务器目录下多了一个oppendonly.aof文件,存储的就是我们执行的命令

AOF的命令也很明显,每次服务器启动都需要进行过程重演,相比RDB更加耗费时间,并且随着我们的操作变多,不断累积,到最后我们的aof文件会变得无比巨大。我们需要改进方案优化这些问题

Redis有一个AOF重写机制进行优化,比如我们执行了这样的语句:

1
2
3
lpush test 666
lpush test 777
lpush test 888

实际上用一条语句也可以实现
lpush test 666 777 888
正是如此,只要我们能够保证最终的重演结果和原有语句的结果一致,无论语句如何修改都可以,所以我们可以通过这种方式将多余语句进行压缩

  1. 我们可以输入命令来手动执行重写操作
    bgrewiteof
  2. 或是在配置文件中配置自动重写
    百分比配置文件中配置自动重写:
    auto-aof-rewrite-percentage 100
    当达到这个大小时,触发自动重写:
    aoto-aof-rewrite-min-size 64mb`
    至此,两种持久化方案介绍结束,最后进行总结

两种方案优缺点

  • RDB
    优点:加载速度快、数据体积小
    缺点:存储速度慢大量消耗资源、会发生数据丢失
  • AOF
    有点:存储速度快,消耗资源少、支持实时存储
    缺点:加载速度慢、数据体积大

三、Redis中事物和锁机制

1. 事物机制:

  • 和MySQL一样,在Redis中也有事物机制,当我们需要保证多余命令一次性完执行而中途不受其他命令干扰时,就可以使用事物机制。
  1. 我们可以使用明里阿尼过来直接开启事物:
    multi
  2. 当我们输入完所有要执行的命令,可以使用命令来立即执行事物:
    exec
  3. 我们也可以中途取消事物:
    discard
  • 实际上整个事物是创建了一个命令队列,它不像MySQL那种在事物中也能单独得到结果,而是我们提前将所有的命令装在队列中,但是并不会执行,而是等我们提交事务的时候再统一执行。

2. 锁:

  • 又提到锁了,实际上这个概念对我来说已经不算陌生了。实际上在Redis中也会出现多个命令竞争同一个数据的情况,比如现在有两条命令同时执行,他们都要去修改a的值,那么这个时候就只能动用锁机制来保证同一时间只能有一个命令操作。

  • 虽然Redis中也有锁机制,但是它是一种乐观锁,不同于MySQL,我们在MySQL中认识的锁是悲观锁。

  1. 悲观锁:时刻认为别人会来抢占资源,禁止一切外来访问,直到释放锁,具有强烈的排他性质

  2. 乐观锁:并不认为会有人来抢占资源,所以会直接对数据进行操作,在操作时再去验证是否有其它人抢占资源

  • Redis中可以使用watch来监视一个目标,如果执行事务之前被监视目标发生了修改,则取消本次事物:
    watch

四、使用Java与Redis交互

既然了解如何通过命令窗口操作Redis数据库,那么我们如何使用java来操作呢?
这里我们需要使用Jedis框架,他能够实现Java与Redis数据库交互,导入依赖:

1
2
3
<groupId><redis.clients></groupId>
<artifactId>jedis</artifactId>
<version>4.0.0</version>