我現在事先擁有1萬個啟用碼,要求使用者請求(能拿到使用者id)時,從這1萬個啟用碼抽出一個給使用者,每個使用者最多隻能拿到1個。
我現在的設計是這樣的:
用redis儲存這個1萬個啟用碼的id(主鍵自增,從1到1萬),當使用者請求時,從redis中拿出一個id。利用redis的原子性,可以保每個請求拿到的都是不同的啟用碼。
然後根據id到mysql裡查到這個啟用碼,狀態置為“已發放”,同時在記錄表裡添加“使用者id,啟用碼id”的記錄,再把啟用碼實際內容返回給使用者。這樣使用者每次請求,先查下記錄表有沒有這個使用者記錄,有的話就表示抽過了返回提示資訊,沒有的話就抽取啟用碼返回給使用者。
本來我以為沒問題的,卻發現實際上記錄表出現了1個使用者拿到2個啟用碼的情況,這2條記錄都是同一秒產生的。我猜測可能是這樣的:某個使用者發出了2次請求,這2次請求的時間間隔非常小,所以導致第2次請求檢測記錄表記錄時,第一次請求的“插入記錄表操作”還沒完成,導致2次請求都通過了。
請問是這個原因嗎?要保證一個使用者最多隻能拿到一個該怎麼做呢?
回複內容:
我現在事先擁有1萬個啟用碼,要求使用者請求(能拿到使用者id)時,從這1萬個啟用碼抽出一個給使用者,每個使用者最多隻能拿到1個。
我現在的設計是這樣的:
用redis儲存這個1萬個啟用碼的id(主鍵自增,從1到1萬),當使用者請求時,從redis中拿出一個id。利用redis的原子性,可以保每個請求拿到的都是不同的啟用碼。
然後根據id到mysql裡查到這個啟用碼,狀態置為“已發放”,同時在記錄表裡添加“使用者id,啟用碼id”的記錄,再把啟用碼實際內容返回給使用者。這樣使用者每次請求,先查下記錄表有沒有這個使用者記錄,有的話就表示抽過了返回提示資訊,沒有的話就抽取啟用碼返回給使用者。
本來我以為沒問題的,卻發現實際上記錄表出現了1個使用者拿到2個啟用碼的情況,這2條記錄都是同一秒產生的。我猜測可能是這樣的:某個使用者發出了2次請求,這2次請求的時間間隔非常小,所以導致第2次請求檢測記錄表記錄時,第一次請求的“插入記錄表操作”還沒完成,導致2次請求都通過了。
請問是這個原因嗎?要保證一個使用者最多隻能拿到一個該怎麼做呢?
在插入mysql的時候再做一次驗證
使用一定的演算法,根據使用者ID產生對應的啟用碼,然後入庫。
保證唯一,而且不會重複。
這樣怎麼樣
用戶端提交一次後在收到傳回值之前不可操作。
一定要callback才解鎖
為什麼不先把"使用者id,啟用碼id"的記錄也先存在redis呢?
直接在redis中存邀請碼的消耗情況不行麼?
如果是不小心被點擊了兩次的話,那為什麼不用JS限制只可以點擊一次呢?或者是在提交的時候產生一個唯一的 token 呢?
這不是可以解決了嗎?
使用者操作加鎖就可以:)
在對db等進行操作前. 根據使用者資訊例如 account 產生md5 key 查詢在memcache中是否有值 不存在key 則set 完成db插入等操作 del掉key