文章目录
Redis的事物
Redis事务和传统关系数据库事务的区别
传统数据库事务过程
在关系型数据库中,我们开启事务并进行一系列的读写操作,最后,用户用户可以选择发送commit来确认之前的修改,或者发送rollback来放弃之前的修改。
Redis事务过程
Redis提供的事务是将多个命令打包,然后一次性、按照先进先出的顺序(FIFO)有序的执行。在执行过程中不会被打断*(在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中),当事务队列中的所以命令都被执行(无论成功还是失败)*完毕之后,事务才会结束。
Redis事务的主要作用就是串联多个命令防止别的命令插队。
事物的使用
在Redis中我没使用一般使用三个命令进行操作
命令格式 | 描述 |
---|---|
Multi | 表示事物的开始,进入命令组队 |
Exec | 将刚刚进行组队的命令按照顺序进行执行 |
Discard | 在还没有使用Exec(执行命令)前使用表示退出组队 |
从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行。
组队的过程中可以通过discard来放弃组队。
Multi
使用之后将命令按照顺序,一个一个进行输入
此时命令并没有执行,只有我没进行Exec命令才会执行
如果组队中命令语法或者判断无法执行 就会出现异常,所有的命令都不会成功
正确情况
组队出现错误
Exec
- 组队时,报错。在执行时,整租所有的命令都会被取消
- 组队时候,不报错。执行时候报错,只有报错的命令不会执行其他的命令正常
执行是错误
Discard
在Exec之前执行可以取消组队
事物的冲突
一个请求想给金额减8000
一个请求想给金额减5000
一个请求想给金额减1000
锁机制
这里先介绍两种锁 乐观锁和悲观锁
乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。
-
悲观锁
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
-
乐观锁
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
乐观锁的使用
在执行multi之前,先执行watch key1 [key2],可以监视一个(或多个) key
如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
测试
这里我们在一个客户端上进行监视一个key的同时,为key命令进行添加组
在上一个客户端还没有exec之前,在第二个客户端进行为监视的key执行命令
执行事物的客户端发现监控的key改变了,在执行exec就不会区执行了
取消 WATCH 命令对所有 key 的监视。
可以在watch监视之后使用UNWATCH命令
如果在执行 WATCH 命令之后,EXEC 命令或DISCARD 命令先被执行了的话,那么就不需要再执行UNWATCH 了。
Redis事务三特性
-
单独的隔离操作
-
事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
-
没有隔离级别的概念
-
队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行
-
不保证原子性
- 事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚
在硅谷的视频中,这里存在一个秒杀示例。大家可以去看一看。
我怕我这里介绍不清楚