欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

使用Redis HASH的VALUE存放了一段JSON字符串,在并发操作时怎么保证JSON字符串的原子性

程序员文章站 2022-06-06 23:36:41
...
假设我在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中存放了这样一条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两个操作可以用事务控制

相关标签: redis php json