php - 數(shù)據(jù)庫與邏輯應(yīng)用分離的情況下怎么保證信息同步,或者叫安全
問題描述
我不太明白這個詞怎么表達
是這樣的,現(xiàn)在有一臺服務(wù)器運行數(shù)據(jù)庫(server),另外一臺運行php程序(client),瀏覽器(Browser)訪問client,然后client邏輯判斷后通過http協(xié)議對server中的數(shù)據(jù)庫進行CURD操作
有個問題就是,如果Browser的用戶操作過快,而server和client之間http請求太慢的話,就會導致client上獲取的數(shù)據(jù)更新不及時,導致一些錯誤。。
栗子:一個用戶只能買一個商品,用戶點擊之后,client先讀取server的數(shù)據(jù),判斷是否已經(jīng)購買,沒有購買的話進行寫入操作,然后購買完成,但是如果用戶連著點擊兩次購買,兩次操作一次進入client,然后由于client和server之間網(wǎng)速或者其他一些問題,寫入操作沒有及時完成,造成兩次購買操作的判斷為此用戶未購買,于是會有兩次寫入server數(shù)據(jù)庫的操作,就會造成錯誤。。
這個問題屬于什么?應(yīng)該怎么解決?
問題解答
回答1:用內(nèi)存數(shù)據(jù)庫或者NOSQL數(shù)據(jù)庫來跟客戶端交互,然后內(nèi)存數(shù)據(jù)庫跟MYSQL這類關(guān)系數(shù)據(jù)庫“同步”。
如果客戶端某些操作需要數(shù)據(jù)庫查詢來判斷,這個時候如果是高并發(fā)的情況很容易就產(chǎn)生錯誤了。以前就經(jīng)歷過,比如用戶注冊判斷是否有重名的,理論上是先查詢數(shù)據(jù)庫是否有該用戶名存在然后插入,然而實際運營中這個邏輯竟然被打破了,發(fā)現(xiàn)了重名用戶。
所以把核心的數(shù)據(jù)放到關(guān)系數(shù)據(jù)庫,對速度有要求的使用內(nèi)存數(shù)據(jù)庫。適當?shù)氖褂镁彺嬉詼p小重復的查詢。
回答2:一般的解決方案是服務(wù)器先提供 token,有 token 才能成功操作,用完就會被標記過期。這樣既可以保證不會重復操作,還可以做限流等功能。
而你的問有些不對題。如果是數(shù)據(jù)庫與業(yè)務(wù)服務(wù)器之間通信的安全性,可以使用 SSL 協(xié)議。
還有一種做法是采用一致性哈希算出業(yè)務(wù) id,不用自增 id。這樣就可以保證很多操作冪等,有興趣可以試試看。
回答3:謝邀,你的栗子客戶端做判斷即可
回答4:分配token之類的當然是非常好的解決方案。不過在實際應(yīng)用中我覺得下面這種方案更加簡潔高效:
前臺js里面處理下,點擊【購買】按鈕后彈出全屏遮罩,阻止用戶點擊第二次,當后臺成功后再把遮罩干掉。此外也可以使用標志位的方式,或者使用經(jīng)典的debounce/throttle算法。
后臺在購買流程中也判斷下,短時間內(nèi)(比如10秒內(nèi))的重復購買的時候直接返回“請不要重復操作”的錯誤。數(shù)據(jù)庫方面可以考慮使用事務(wù)并把事務(wù)的隔離級別提高,或者使用鎖。
一般前臺js里面處理下后,很多問題都能避免了。除非有惡意用戶。
回答5:加并發(fā)鎖,可以使用redis,memcached等,當一條請求完成后再釋放鎖
// 操作的原子性,如該key在有效時間30秒被設(shè)置過返回0,一般請求超時為30秒$redis->set($lock_key, 1, array('NX', 'EX'=>’30’));回答6:
從上面看你有兩臺服務(wù)器,一臺運行php的server,另外一臺db的server。然而你兩臺server之間的通訊為什么要使用http協(xié)議呢?而不是走mysql(假設(shè)你用的是mysql)默認的連接協(xié)議了?也就是說你應(yīng)該在php中直接連到你server的數(shù)據(jù)庫,然后操作DB。
對于你例子中提到的連續(xù)插入問題,可以通過表結(jié)構(gòu)設(shè)計來完成,可以給字段添加唯一索引UNIQUE。另外還有一些其它方法,個人比較推薦唯一索引做法
