假設我在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兩個操作可以用事務控制