資料庫重複寫入問題分析

2022-07-02 08:24:11 字數 1840 閱讀 7195

為了提高系統的吞吐量,很多環節下對於資料庫的寫入是多執行緒,甚至是多程序的。為了保證寫入成功,在很多情況下需要多次重試。這就會帶來乙個問題,資料重複,同一條資料會被記錄多次。有些情況下資料重複無傷大雅,但是很多情況系統是無法容忍資料重複的。因此這個問題需要解決。我個人覺得解決這一問題有兩個方向:第一,從資料庫上保證資料不重複,第二,從程式上保證資料不重複。

資料庫上解決主要包括:主鍵,唯一性索引,甚至是臨時表。程式上解決無非就是要保證同步,這兩種方式能解決很多情況下的資料重複。但是有些情況可能比較棘手,使用者兩種方法有時並不能很好的解決,或實現起來比較複雜,如下面的資料

假如下表主要字段如下:id  studentid  teacherid  states 

狀態(states)是有多種的(0,1,2,3),狀態可以轉換,但是狀態為,0的乙個只能由乙個,其它欄位是可以重複的。這個其實就是保證某一種狀態下的資料不重複。首先唯一性索引不能夠起作用,因為無法建立唯一性索引。主鍵也沒有效果,沒法通過這些字段生成可區分的id。所以這兩種方法都失效了。還有一種方法就是臨時表,在臨時表中插入一條能夠區分的資料(比如studentid,teacherid組合),無論是唯一索引還是主鍵都可以。寫入時首先寫臨時表,臨時表寫入成功則插入一條資料,然後清空臨時表。這在嚴格保證資料不重複的情況下是能夠起作用的,但是比較繁瑣,需要處理乙個臨時表。另外的乙個辦法就是根據我們的業務場景,在乙個時間段內(比如1分鐘)不會出現兩條相同資料寫入。這樣我們可以使用studentidteacherid加上精確到分鐘的時間來構成乙個唯一id,重試時間間隔一般都極短(秒級別),這樣通過id來保證資料的唯一性。

如果從程式上來保證資料不重複,則更加複雜。第一種辦法是對寫入過程加鎖,確保只有一次寫入成功**如下(偽**):

lock lock =new

writelock();

public

void

write(data data)

} }finally

}

這種方式首先會存在效率問題,所有的資料都要順序寫入會匯入效率下降。我們只需要保證同一條資料不能併發寫入而不是不同資料。另外這種方式還會存在一定概率的重複,因為網路問題和資料庫或orm框架的快取問題,會導致寫入檢測時並不能發現資料庫的更新。比如使用hibernate,兩次執行緒呼叫write方法會使用兩個session,從而使得第一次寫入快取的資料無法在下一次操作中看到。在write方法中多次呼叫numberof方法也是不起用的,由於session的快取,後面的查詢會使用第一次的快取結果,在第一次查詢後的資料庫變化,後面的查詢仍然無法覺察。

針對寫入效率低的問題,這裡可以採用資料鎖,即通過一種方法比如使用data的hashcode來對映來獲取鎖,這樣不同的資料會獲取到不同的鎖,解決了所有資料的順序寫入問題。但是跟第一種情況一樣仍會存在資料重複問題。

對於多程序的情況,如微服務部署多個的情況,上面的同步會失效。對於這種情況唯一的解決辦法就是使用上面所說的資料庫同步或者構造乙個環節鎖,類似於令牌的方法。只有獲取到令牌才有寫入資格,寫入成功後銷毀針對該資料的「令牌「。這種實現其實也比較簡單,如使用乙個redis的hashmap,每次寫入首先獲取該資料對應的value,通過value來判斷該資料是否寫入,來保證資料不重複。

上面無論哪種方法,針對本文所提到的資料,解決重複問題都是不容易的。要麼實現起來比較複雜,要麼還是不能100%保證資料不重複。針對我們的業務場景:state為0的狀態下資料能有一條,且0的狀態不會持續太久,後面的操作會將其修改。而且多執行緒重試並不是每次都發生的,多程序情況下,每次資料寫入也多是只通過其中乙個節點,針對這種情況其實可以採取更簡單的處理方式,不做過多的順序限制只在寫入時檢查資料庫,如果真的因為資料更新或者併發導致了多次寫入也沒有關係(這種情況很少),後續的操作時再刪除多寫入的資料。這是一種樂觀的處理方式,但是對於很多情況是可以解決資料重複問題的。

PHP技巧 何避免頁面重新整理資料重複寫入資料庫

何避免頁面重新整理資料重複寫入資料庫 當表單的資料是提交給本頁面處理並寫入資料庫時,點提交後,重新整理頁面的話使資料重複寫入資料庫。網上搜尋一下,發現了不少的解決方案 一 把一頁面分開為兩個,資料提交給另乙個頁面處理,之後再跳到輸入頁面。優點 避免了重新整理的影響,並可連續提交資料。缺點 當使用者在...

資料庫資料重複問題

關於重複資料的主要問題是重複資料的型別和怎樣刪除重複資料 一 重複資料的型別 1.兩行資料完全一樣,即所有欄位都是相同的值 此型別用group by或distinct就可以解決 2.兩行資料部分字段相同,不重複的字段不重要。二 刪除重複資料的場景 場景1 資料在資料庫中直接刪除,再進行其他操作 方法...

陣列資料迴圈寫入資料庫的問題

if request action do then set lr sp server.createobject adodb.recordset if ubound arr1 0 then lr sp insert into dongtai test buzhou1,shuoming1 values ...