資料庫Update操作的一些技巧總結

2021-07-25 00:26:21 字數 1506 閱讀 8524

問題背景:

在高併發場景下,當多個任務同時操作同一條資料表記錄時,需要保證資料一致性。

場景舉例:

預付款充值場景,假設使用者建立一筆賬單用於充值,在充值前,系統將賬單狀態status置位「待支付」,當系統在收到成功充值的通知後,會設定status為「成功支付」,並累計餘額。但由於一些原因,系統可能會收到多條同樣的充值成功訊息。系統針對每條訊息都設定狀態,雖然不會對賬單的status本身產生負面影響,但每次都成功處理後,必然會導致餘額重複增加,這顯然是系統不希望達到的預期(當然使用者本身是樂意的,白賺了,^v^)。為此,系統需要保證即使在收到重複通知時,只成功設定一次賬單的狀態,由「待支付」遷為「成功支付」,從而保證只對餘額增加一次。

解決方案:

一般情況下,我們會通過在業務層面先判斷賬單的status為「待支付」時,才update狀態為「成功支付」,其他非「待支付」場景,業務直接返回錯誤,即:

if(billentity.status != "待支付")

else

但在高併發場景下,如果兩個操作同時判斷出status狀態都為」待支付」,則依然會執行多次成功的update操作。

為此,我們在資料庫層面也增加保護措施,通過增加約束的方式來執行update操作。具體方案如下:

where bill_id=$id and status = "待支付"";

if( context.dosql(sql) <= 0 )

在資料庫中,當第二次執行update操作時,由於status在資料庫中的值已經為「成功支付」,所以第二次update操作影響的記錄個數會等於0,導致更新失敗,從而保證了業務層面不會繼續執行後續的邏輯。

場景舉例:

預付款充值場景,假設使用者的餘額初始為100元,現在通過兩台裝置同時充值50元,則在兩筆充值都成功的情況下,使用者的餘額應該變為200元。假設採用不帶約束的update方式進行餘額修改,即如下的sql語句:
update  t_balance  set balance = $newbalance
在併發操作時,如果以如下的順序併發執行:

a查出初始餘額為100元;

b查出初始餘額為100元;

a改寫餘額為100+50元;

b改寫餘額為100+50元。

很顯然,由於第二次update改寫操作直接覆蓋了第一次的操作,導致最終的餘額不符合預期。

解決方案:

這裡我們可以根據增量更新的方式,每次update操作,不是將最終計算的結果先在業務層計算得出後寫入資料庫,而是將計算的邏輯放在資料庫層去執行。於是改寫後的update語句變為:

update t_balance set balance = balance + 50

通過增量更新,即使在併發場景下,也能保證每次update使用的舊值都為資料庫中的最新值。

一些資料庫的操作

建立乙個資料庫 create database database name 刪除乙個資料庫 drop database database name 顯示資料庫 show databases 進入某個資料庫 use database name 建立乙個資料表 create table database...

資料庫 資料庫sql一些操作

空關係 none 方法返回可以在鏈式呼叫中使用的 不包含任何記錄的空關係。在這個空關係上應用後續條件鏈,會繼續生成空關係。對於可能返回零結果 但又需要在鏈式呼叫中使用的方法或作用域,可以使用 none 方法來提供返回值。article.none 返回乙個空 relation 物件,而且不執行查詢 下...

Oracle資料庫的一些操作

如何備份oracle資料庫 md f db bak date 0,10 exp userid bszlhr bszlhr orcl 14 file f db bak date 0,10 bszlhr date 0,10 dmp log f db bak date 0,10 log bszlhr da...