127.0.0.1:6379> multi #开启事务 OK 127.0.0.1:6379> set name dingyongjun #添加数据 QUEUED 127.0.0.1:6379> set age 26 #添加数据 QUEUED 127.0.0.1:6379> set high 172 #添加数据 QUEUED 127.0.0.1:6379> exec 执行事务 1) OK 2) OK 3) OK 127.0.0.1:6379> get name #获取数据成功,证明事务执行成功 "dingyongjun" 127.0.0.1:6379> get age "26"
②放弃事务
1 2 3 4 5 6 7 8 9 10
127.0.0.1:6379> multi #开启事务 OK 127.0.0.1:6379> set name dingyongjun #添加数据 QUEUED 127.0.0.1:6379> set age 26 #添加数据 QUEUED 127.0.0.1:6379> discard #放弃事务 OK 127.0.0.1:6379> get name #不会执行事务里面的添加操作 (nil)
③编译时异常,代码有问题,或者命令有问题,所有的命令都不会被执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14
127.0.0.1:6379> multi #开启事务 OK 127.0.0.1:6379> set name dingyongjun #添加数据 QUEUED 127.0.0.1:6379> set age 23 #添加数据 QUEUED 127.0.0.1:6379> getset name #输入一个错误的命令,这时候已经报错了,但是这个还是进入了事务的队列当中 (error) ERR wrong number of arguments for'getset'command 127.0.0.1:6379> set high 173 #添加数据 QUEUED 127.0.0.1:6379> exec#执行事务,报错,并且所有的命令都不会执行 (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> get name #获取数据为空,证明没有执行 (nil)
④运行时异常,除了语法错误不会被执行且抛出异常后,其他的正确命令可以正常执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
127.0.0.1:6379> multi #开启事务 OK 127.0.0.1:6379> set name dingyongjun #添加字符串数据 QUEUED 127.0.0.1:6379> incr name #对字符串数据进行自增操作 QUEUED 127.0.0.1:6379> set age 23 #添加数据 QUEUED 127.0.0.1:6379> get age #获取数据 QUEUED 127.0.0.1:6379> exec#执行事务。虽然对字符串数据进行自增操作报错了,但是其他的命令还是可以正常执行的 1) OK 2) (error) ERR value is not an integer or out of range 3) OK 4) "23" 127.0.0.1:6379> get age #获取数据成功 "23"
⑤总结:由以上可以得出结论,Redis是支持单条命令事务的,但是事务并不能保证原子性!
Redis如何实现乐观锁?
①watch(监视)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
127.0.0.1:6379> set money 100 #添加金钱100 OK 127.0.0.1:6379> set cost 0 #添加花费0 OK 127.0.0.1:6379> watch money #监控金钱 OK 127.0.0.1:6379> multi #开启事务 OK 127.0.0.1:6379> DECRBY money 30 #金钱-30 QUEUED 127.0.0.1:6379> incrby cost 30 #花费+30 QUEUED 127.0.0.1:6379> exec#执行事务,成功!这时候数据没有发生变动才可以成功 1) (integer) 70 2) (integer) 30
②多线程测试watch
线程1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#线程1 127.0.0.1:6379> set money 100 #添加金钱100 OK 127.0.0.1:6379> set cost 0 #添加花费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 #金钱-20 QUEUED 127.0.0.1:6379> INCRBY cost 20 #花费+20 QUEUED #这里先不要执行,先执行线程2来修改被监视的值 127.0.0.1:6379> exec#执行报错,因为我们监视了money这个值,如果事务要对这个值进行操作前 #监视器会判断这个值是否正常,如果发生改变,事务执行失败! (nil)