事务是什么,我认为事务是不成功,便成仁;
事务是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。
但是在redis中,事务中是不存在原子性的。
一,redis是一群命令的组合,每个命令在一条队列中,顺序执行;
一个事务中所有的命令都会被序列化,在执行任务的时候,顺序执行。
二,redis事务没有隔离级别的概念;
三,redis的三个阶段
1)开始事务;
2)命令进入队列;
3)执行命令。
四,redis的相关命令
1)multi 开启事务;
2)watch key1 ..... keyn,监视一个或者多个key,如果在事务执行之前,被监视的key被其他命令改动,则事务被打断。
3)exec:执行所有命令;
4)unwach:取消对所有key的监控;
5)discard:取消事务,放弃事务块中的所有命令;
五,指令实例
1)事务的基本过程
开启事务,命令进入序列中,执行命令;
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set name laoli
QUEUED
127.0.0.1:6379> set sex boy
QUEUED
127.0.0.1:6379> set age 30
QUEUED
127.0.0.1:6379> keys *
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) OK
4) 1) "score_ch"
2) "sex"
3) "name"
4) "age"
2)在事务中,入队的命令中其中有一个命令有错误,事务中所有的命令是不执行的;
3)在事务中,入队的命令是存在语法性的错误,在执行其他命令时候,其他的命令是可以正常执行的,错误的命令会抛出异常;
六,悲观锁和乐观锁
在事务中,事务是有原子性的,事务是可以回滚的;
但是在redis中,事务是非原子性的,如何让事务有回滚的能力,需要借助wath命令去监控命令去实现。
1)乐观锁:开启事务前,设置对数据的监听,EXEC时,如果发生数据发生过修改,事务会自动取消(DISCARD)
认为什么事情,都不会出现问题,都是乐观的,不会上锁;
监控money:正常执行;
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20
如果在监视的money中,发生了变化,则事务会自动取消
新开一个线程,添加让money变成1000
127.0.0.1:6379> get money "80" 127.0.0.1:6379> set money 1000 OK 127.0.0.1:6379>
在开线程之前,首先watch money,然后开始事务,然后新开一个线程,让money变成1000,就是执行上面的代码;然后money减去10元,out添加10元,exec后,出现nil
127.0.0.1:6379> get money "80" 127.0.0.1:6379> watch money OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> decrby money 10 QUEUED 127.0.0.1:6379> incrby out 10 QUEUED 127.0.0.1:6379> exec (nil)
上面的案例可以看出,乐观锁在监控到元素发生变化是,取消操作;
解决办法是,放弃监视,重新执行;
127.0.0.1:6379> UNWATCH OK 127.0.0.1:6379> watch money OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> decrby money 10 QUEUED 127.0.0.1:6379> incrby out 10 QUEUED 127.0.0.1:6379> exec 1) (integer) 990 2) (integer) 30
2)悲观锁:
认为任何事情,都会出现问题,都是悲观的,很消耗性能;
我们在sql中使用的for update,应用程序的层面手工实现数据加锁保护操作