使用Redis HASH的VALUE存放了一段JSON字符串,在并发操作时怎么保证JSON字符串的原子性
HSET player Mike "{\"height\":180,\"isAlive\":true}"
接着假设php中有2个并发操作,都是HGET这段json,json_decode成php数组.
然后对其中某个value进行操作.json_encode后再HSET回去.
比如
一个操作将isAlive设置成false,
另一个操作是将height改成181,
那么这下很可能发生意外情况-----第二个操作在前一个操作将数据HSET到数据库之前将数据HGET了去
哦..这下糟糕了
本来前一个操作已经将人给弄死了,结果后一个操作又将人复活了..
然后,试想一下更多并发操作更多的VALUE...
有没有什么好办法能保证这段JSON的原子性呢?
回复内容:
假设我在Redis中存放了这样一条HASH
HSET player Mike "{\"height\":180,\"isAlive\":true}"
接着假设php中有2个并发操作,都是HGET这段json,json_decode成php数组.
然后对其中某个value进行操作.json_encode后再HSET回去.
比如
一个操作将isAlive设置成false,
另一个操作是将height改成181,
那么这下很可能发生意外情况-----第二个操作在前一个操作将数据HSET到数据库之前将数据HGET了去
哦..这下糟糕了
本来前一个操作已经将人给弄死了,结果后一个操作又将人复活了..
然后,试想一下更多并发操作更多的VALUE...
有没有什么好办法能保证这段JSON的原子性呢?
你说的问题的确存在,你这里涉及到的问题其实就是普遍的读-改-写,redis可以保证每个操作的原子性,但是无法保证多个操作的原子性,解决的方法可以使用redis提供的multi和watch命令,具体使用如下:
1.watch住你想要读取的key
2.multi开启事务
3.读取key的内容
4.修改value内容
5.更新key内容
6.exec提交事务,如果在2-6之间发生key的value发生了变化,那么会报错。
以上所说只是redis能够提供的最大的原子性操作,但是对于你的问题是没有任何帮助的,因为在事务中执行的命令只有等到事务提交之后才能获取返回值,但是你的更改需要基于前一步的结果进行操作,那么事务不提交你也就无法获取到原来的内容,所以无法更新。
解决办法是把json格式字符串使用redis的hash结构进行保存,更新的时候直接更新hash下的一个key即可,这样也就不会出现并发了,但是如果你还是需要基于原始的值进行判断然后再修改,那么问题还是跟上面说的一样,没有任何变化。
redis是单线程模型,不用担心这个问题
hget和hset两个操作可以用事务控制