我们现在基本都是使用mysql来实现对金额的操作,保证数据的准确性,那能不能使用redis来对金额进行操作并保证数据的准确性呢?可以利用 redis 的事务来实现这个想法。
redis 的 WATCH 和 EXEC 可以提供类似事务的机制:WATCH观察key是否被改动,如果提交时key被改动,EXEC将返回null,表示事务失败。
假设redis客户端执行:
$money = GET key $money = $money - $diff SET key $money
在并发量大的时候可能会出现并发一致性问题,可以在redis客户端这样执行:
WATCH key $money = GET key $money = $money - $diff MULTI SET key $money EXEC
在 WATCH 之后,EXEC 执行之前,如果key的值发生变化,则EXEC会失败。redis的WATCH本质上使用的就是乐观锁CAS机制来保证事务性。
可能有的同学会有疑惑,Redis不是单线程运行的吗,为什么还需要事务来保证一致性呢?
Redis虽然是单线程运行命令,但是它可以拥有多个连接,Redis在接收各个连接发送的命令不是按块接收,意思是客户端发送给Redis的多个命令被接收时可能中间也会有其他客户端的命令,所以我们需要MULTI、EXEC命令来实现事务功能。
那又有同学可能会有疑惑,既然都实现事务功能了,为什么还需要 WATCH 命令来监视数据呢?
这个其实和上面说的原因也是一样的,Redis接收命令的顺序客户端是控制不了的,所以如果多个客户端同时发送一些包含在事务中的命令给服务端,Redis会按接收命令的顺序来执行这些事务命令,这样就有可能导致后面执行的客户端使用的不是自己想要的数据。所以我们使用WATCH 命令来监控数据的状态,如果在提交时数据被更改那么就会提交失败,这就是使用到乐观锁的地方。