事务
Redis事务本质:一组命令的集合。一个事务中的所有命令都会被序列化,在事务执行过程中,会按顺序执行。
一次性、顺序性、排他性!执行一系列的命令。
Redis单条命令保证原子性,但是事务不保证原子性!
Redis事务没有隔离级别的概念,所有的命令在事务中并没有直接被执行,只有发起执行命令的时候才会执行。
Redis的事务:
- 开启事务
- 命令入队
- 执行事务
正常执行事务
- 开启事务 multi
- …
- 执行事务 exec
放弃事务
discard命令,执行后事务队列中命令再不会被执行。
错误
错误有两种
-
编译型异常(代码有问题),事务中所有的命令都不会背执行
-
运行时异常,会跳过有错误的部分,其他命令可以正常执行,错误命令抛出异常。
监控
悲观锁:
-
认为什么时候都会出问题,无论做什么都会加锁
上厕所的时候认为一定会有人推你的门,所以要锁上厕所门
-
可能会影响效率
乐观锁:
- 认为什么时候都不会出现问题,所以不会上锁,在更新数据的时候去判断一下在此期间是否有人改动过数据。
- 获取version
- 更新的时候比较version
乐观锁并不真正加锁,而是在提交操作的时候对比一下version。
Redis监视测试
watch监视money,正常执行情况:
注意一旦事务结束,watch会自动失效。
如果在事务执行过程中事务被中断并且被watch的变量发生了改变,则事务会执行失败。
模拟一下这种情况,先写好这些代码
先不提交事务,然后开另外一个客户端修改一下money的值
再在这里提交事务
可以发现事务没有被执行。
执行失败之后,先解锁watch的变量,再重新watch。
相当于先放弃之前的version变量,然后保存最新的version变量。
使用unwatch解锁变量。
整个流程相当于,先使用watch给指定变量加上乐观锁,然后在执行事务的时候,会对比监视变量的version和加锁的时候变量的version,如果相同就执行,不同就不执行。
Jedis
使用Java来操作redis
什么是 Jedis
是redis官方推荐的Java连接开发工具,使用Java操作redis中间件。
测试
-
导入依赖
<dependencies> <!--导入Jedis包--> <!-- https://mvnrepository.com/artifact/redis.clients/jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>4.3.1</version> </dependency> <!--faseJson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>2.0.16</version> </dependency> </dependencies>
-
编码测试
-
连接数据库
public class TestPing { public static void main(String[] args) { Jedis jedis = new Jedis("localhost", 6379); String ping = jedis.ping(); System.out.println(ping); } }
jedis的所有方法就是redis数据库中的各种指令。 -
操作命令
-
断开连接
-
SpringBoot整合
SpringBoot操作数据:spring-data
在SpringBoot2.x之后,原来的jedis被替换为了lettuce
jedis: 采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全,使用Jedis pool连接池。更像BIO模式。
lettuce: 采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况,可以减少线程数量。更像NIO模式。
-
导入依赖
在创建项目的时候勾上对应的包 -
配置测试
# 配置redis spring.redis.host=localhost spring.redis.port=6379
-
测试
@SpringBootTest class Redis02SpringbootApplicationTests { @Autowired RedisTemplate redisTemplate; @Test void contextLoads() { // redisTemplate, 操作不同的数据类型 // opsForValue 操作字符串 类似string // opsForList 操作list // opsForSet // opsForHash // opsForZSet // opsForGep // opsForHyperLogLog // 出了基本的操作,常用方法可以直接通过redisTemplate操作, 事务和基本的CRUD // // 获取redis连接对象 // RedisConnection connection = redisTemplate.getConnectionFactory().getConnection(); // connection.flushDb(); // connection.flushAll(); redisTemplate.opsForValue().set("mykey", "test"); System.out.println(redisTemplate.opsForValue().get("mykey")); } }
Redis配置
启动的时候,需要指定的配置文件
单位
对单位的大小写不敏感
包含
一个配置文件可以包含其他的配置文件
网络
通用
daemonize yes # 以守护进程方式运行,默认是no
pidfile /var/run/redis_6379.pid # 如果以后台的方式运行,我们就需要指定一个pid文件
# 指定日志的级别
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice
logfile "" # 日志的文件名,为空的话就是标准输出
databases 16 # 数据库的数量,默认为16
always-show-logo yes # 是否显示logo
快照
持久化,在规定的时间内,执行了多少次操作,则会持久化到文件 .rdb .aof
redis 是内存数据库,如果没有持久化,那么断电后数据就丢失了。
# Unless specified otherwise, by default Redis will save the DB:
# * After 3600 seconds (an hour) if at least 1 key changed
# * After 300 seconds (5 minutes) if at least 100 keys changed
# * After 60 seconds if at least 10000 keys changed
#
# You can set these explicitly by uncommenting the three following lines.
#
# 如果3600秒内,如果至少有1个key进行了修改,我们就进行持久化操作
# save 3600 1
# save 300 100
# save 60 10000
stop-writes-on-bgsave-error yes # 持久化如果出错,是否还需要继续工作
rdbcompression yes # 是否压缩rdb文件(持久化文件)需要消耗一些CPU资源
rdbchecksum yes # 保存消息到rdb文件时计算出校验码
dir /usr/local/var/db/redis/ # rdb文件保存的目录
安全
requirepass foobared # 可以在配置文件里面加密码
也可以在客户端给服务端加密码。
限制
maxclients 10000 # 设置最大客户端数量
maxmemory <bytes> # 设置内存上限
# volatile-lru -> Evict using approximated LRU, only keys with an expire set.
# allkeys-lru -> Evict any key using approximated LRU.
# volatile-lfu -> Evict using approximated LFU, only keys with an expire set.
# allkeys-lfu -> Evict any key using approximated LFU.
# volatile-random -> Remove a random key having an expire set.
# allkeys-random -> Remove a random key, any key.
# volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
# noeviction -> Don't evict anything, just return an error on write operations.
maxmemory-policy noeviction # 内存达到上限的处理策略
APPEND ONLY模式配置( AOF配置)
appendonly no # 默认不开启aof模式,默认使用rdb方式持久化,大部分情况下,rdb方式够用了
appendfilename "appendonly.aof" # aof持久化文件的名字
# appendfsync always # 每次修改会同步,消耗性能
appendfsync everysec # 每秒同步一次,可能会丢失1s的数据
# appendfsync no # 不执行同步,这个时候操作系统自己同步数据,速度最快
Redis持久化
RDB(Redis DataBase)
在指定的时间间隔内将内存中的数据集体写入磁盘,也就是形成了一个快照,恢复时将快照文件直接读到内存里面。Redis会单独创建一个子进程来进行持久化,会现将数据写入到一个临时文件中,待持久化过程结束了,再用临时文件替换上次持久化的文件。整个过程中主线程不进行任何IO操作,保证了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加高效。RDB的缺点是最后一次持久化之后的数据可能丢失(最后的数据没来得及持久化)。
rdb保存的文件默认是dump.rdb。
手动执行save命令或者满足自动存储条件的时候,会进行持久化。
- 优点
- 适合大规模的数据恢复,把快照直接还原到内存中
- 缺点
- 需要一定的时间间隔进行保存,如果redis以外宕机了,最后一次修改数据就没有了
- fork进程的时候,会占用一定的内存空间
AOF (Append Only File)
将我们所有的命令都记录下来,history,回复的时候就把这个文件全部再执行一遍。
以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(不包括读操作),只允许追加文件但不允许改写文件,redis启动之初会读取该文件重新构建数据。
AOF保存的是appendonly.aof
默认不开启,需要手动开启,重启服务器之后生效。
进行几次操作后可以看到出现了appendonly.aof文件,并且里面记录了刚刚使用的赋值命令。
如果appendonly.aof文件被破坏之后,可以发现服务器无法启动。
这时候我们需要使用redis提供的 redis-check-aof 工具来对这个文件进行检测并修复
这个工具会把被破坏的部分数据直接删除。
-
优点
- 同步配置,可以提高效率
- 丢失数据更少
-
缺点
- 相对于rdb文件来说,aof文件更大,载入速度也更慢
拓展
-
RDB持久化方式能够在指定时间间隔内对数据进行快照存储
-
AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以Redis协议追加保存每次写的操作到文件末尾,Redis还能对AOF文件进行后台重写(合并指令),使得AOF文件体积不会过大。
-
只做为缓存时,可以不使用任何持久化
-
同时开启两种持久化方式
- redis重启时会有效载入AOF文件来恢复原始数据,因为在通常情况下AOF文件保存的数据更加完整
- RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。但是相对于AOF来说,RDB文件变化慢,更容易备份,而且恢复速度快,不会有AOF潜在的BUG