4.1 简介
和sql的事务一样,本质是一组命令的集合,一个事务中所有命令都会序列化,按顺序地串行执行而不会被其他命令插入加塞.(要么一起成功,要么一起失败)
一个队列中一次性、顺序性、排他性的执行一系列的命令
4.2 应用场景
- 秒杀系统
网络上经常谈到的微信抢红包项目为例:1
2
3
4
5
6
7
8
9
10
11
121.设计数据库字段
红包id、发红包人、金额、数量、剩余金额、剩余数量、抢到人的名单、过期时间、添加时间等
发红包时入库,并在redis储存红包id:金额,红包id:数量
基于微信用户量来说这显然是一个秒杀系统,存在高并发。
2.抢红包设计
用redis的list构建抢红包队列和打开红包的队列,进入抢红包队列前n个人的获取可以打开红包的token,
其余人则直接获得无效token(无效请求),然后是打开红包的操作,点击打开即加入打开红包队列,同时
记录该人的分配金额(分配算法,要满足在最后一个前不把钱扣完),同时用事务将缓存的数量、金额减少
然后最后一个人分配剩余金额,金额发放用异步的方式进行(消费者消费打开红包队列),最后达到最终一致性。
反正事务都有一个目的,保证几步操作的原子性,不过redis的不一定能保证。。。。 - 支付系统
4.3 基本使用
命令:
1.Multi
标记一个事务块的开始。
事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行。2.exec
执行所有事务块内的命令。
假如某个(或某些) key 正处于 WATCH 命令的监视之下,且事务块中有和这个(或这些) key 相关的命令,那么 EXEC 命令只在这个(或这些) key 没有被其他命令所改动的情况下执行并生效,否则该事务被打断(abort)。3.discard
取消事务,放弃执行事务块内的所有命令。
如果正在使用 WATCH 命令监视某个(或某些) key,那么取消所有监视,等同于执行命令 UNWATCH 。4.watch
监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。5.unwatch
取消 WATCH 命令对所有 key 的监视。
如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了。
因为 EXEC 命令会执行事务,因此 WATCH 命令的效果已经产生了;而 DISCARD 命令在取消事务的同时也会取消所有对 key 的监视,因此这两个命令执行之后,就没有必要执行 UNWATCH 了。
1 | 1.正常执行 |
5.watch监控
1.监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
2.一旦执行了exec、discard之前加的监控锁都会被取消掉
3.通过watch命令在事务执行之前监控了多个keys,倘若在watch之后有任何key的值发生了变化,exec命令执行的事务都将被放弃。
4.4 锁机制
- 1.悲观锁
pessimistic lock每次去拿数据的时候都认为别人会修改,所以在每次那拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁,读锁,写锁等,都是在操作前先上锁。 - 2.乐观锁 Optimistic lock
每次拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。
(提交的版本必须大于记录当前版本才能执行更新)
4.5 总结
- 1.单独的隔离操作
事务中的所有操作都会序列化、按顺序执行。事务在执行的过程中,不会被其它客户端发送来的命令请求所打断 - 2.没有隔离级别的概念
队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行 - 3.不保证原子性
一条命令执行失败,其他的命令依然会被执行,没有回滚。