PHP高並發下的數據同步的解決方法?
資料庫有個表tb_add
程序的要求是如果tb_add這個表的數據超過1W行,就不允許在插入數據。程序的處理流程如下:第一步:先查詢tb_add現在有多少行第二步:如果不超過1W行,則可以寫入數據那麼問題來了,如果並發量大的情況下,如果數據剛好差1行就滿1W,是否會出現以下情況:
例如有2個用戶,A和B,他們同時在瀏覽器執行了提交,導致這個用戶同時執行第一步,所以他們的都符合插入數據的條件,然後都被指定了第二步,最終的結果就是資料庫變成了10001行。問1:是否會出現以上的情況?問2:在不鎖表的情況下(因為會拖慢速度),如何解決這這樣的問題?ps:目前本人自己的解決方法就是,插入數據後,反查一下資料庫是否超過1W行,超過則刪除本次添加的數據,但是問題又來了,如果2個用戶同時執行了反查的操作,那麼又會同時刪除2條數據,變為9999。。。謝謝熱心人解答。
啊,這個需求好奇怪。問一:很可能會出現,取決於你的網站的請數量。問二:首先考慮能不能不解決,在發現以後把多出來的數據刪掉。其次難道不能提前建好1w條數據,然後每次都去update么?
隊列也是鎖……
默默的說……
用一個計數器
我最近在做一個項目 高並發選課系統每次insert之前先計數器+1然後判斷他的值是否大於max如果大於max計數器自減1 類似回滾如果小於max 執行insert語句ps:計數器自增和自減需要保證其原子性
推薦Redis來做計數器 max也可以用redis來存.我昨天做了一個並發1000的測試 數據錯誤率為0在不修改業務的情況下,必須上鎖。如果後期性能遇到瓶頸,在不提升硬體性能的條件下,優化方式只有降低鎖層次,或修改業務。
有人說排隊,其實排隊也是一種鎖。
扯幾句題外話:
現在網上的誤導文章太多了,各種高並發情況下的不鎖、無鎖。有時候真想問候作者的各種親朋好友。同時,很多連資料庫手冊都沒耐心看完的小屁孩,看到那種無鎖的文章,連原理都沒去理解,就屁顛屁顛地照搬過來。不出問題才怪。而且以後遇到高並發情況,還趾高氣揚地來一句:必須無鎖。想到那場面老夫就想一巴掌拍過去。共享一個鎖,或者隊列
首先,我們從邏輯上去看你的問題的前置條件:超過1w行則不寫數據。
那麼我大概想了這些幾個情況:1.加鎖
缺點:降低性能優點:減少代碼邏輯複雜度(題主現在這樣超過1w條就刪數據的邏輯,感覺看起來就點糟糕啊,如果整個系統一複雜,這樣的來回寫數據,你確定你的邏輯還維護得下去?建議題主梳理一下代碼的邏輯流)
2.隊列(redis/各類mq等)
缺點:引入其他組件,增加系統複雜度,降低穩定性。優點:能夠將web的並行邏輯串列,其實和加鎖差不多,不過更優雅,並且性能上面也更可控。如果題主的系統的邏輯複雜,推薦採用這種。建議:php寫多你會發現,它的邏輯就是一波流的。在它的邏輯層實現過多的重試,等待,以及回寫,會導致php很臃腫。建議要麼在資料庫層上鎖,要麼引入隊列等待,要麼就直接報錯,讓用戶F5重試,如果用ajax重試,幾乎沒有用戶體驗上的問題。那麼來說一下直接報錯的方案。
3.建一個計數器表
舉例:create table store_count (total int(11) NOT NULL) ENGINE=InnoDB搶計數器:如果我查出來現在總數是2,那麼我 update store_count set total = 3 where total = 2如果更新成功,說明現在的總行數是3,可以去插表,如果未更新,說明這時已經有其他用戶插入了,直接給用戶報錯,讓他下次請求再來過。
缺點:這種方式其實比前兩個更粗暴,前2種方式還是等待的,這種方式直接丟棄了部分用戶流量,帶來的是一個有緩存特性的計數器來實現題主提的邏輯。
這個計數器在內存中效果更佳。建議題主根據自身的系統狀況,和代碼邏輯,進行性能、開發效率、邏輯成本、維護成本上的取捨。上鎖,commit。backroll
用隊列唄
應用層加個計數器
感覺拋開業務目標,抽離出來看實現方法,看得人渾身彆扭。比如,業務本身的目標是什麼?為什麼選擇了通過一個錶行數來控制數量的技術方案?肯定沒有別的方案了么?不是什麼樣的奇怪問題,都非要硬著頭皮解決啊……
加鎖就行,要麼鎖表,要麼鎖程序,加了鎖就相當於變成隊列執行,一次只能一個人拿到鎖,只能一個人通過,去插入數據。
php里可以使用文件鎖,或memcached鎖也行,文件鎖會導致阻塞。
可以搜索:php鎖,php文件鎖推薦閱讀:
※用MySQL WHERE進行過濾
※pandas數據保存至Mysql資料庫
※MySQL訓練——Self join@sqlzoo.net
※為何Redis用樂觀鎖,而MySQL資料庫卻沒有?
※為什麼我不再看好MariaDB