1. 程式人生 > >日常總結 postgresql批量刪除 mybatis動態sql spring事物

日常總結 postgresql批量刪除 mybatis動態sql spring事物

今天在寫業務程式碼時,需要寫一個刪除資料庫記錄的方法。然而要操作的表被其他的表依賴。也就是本表的主鍵是其他表的外來鍵。但是資料庫並沒有設計外來鍵,所以只能手動刪除關聯表的資訊  。用的框架是spring,dubbo,mybatis,資料庫是postgresql。因為設計到多條sql語句。當然要用事務來解決資料的一致性和完整性的問題。下面先來重新學習一下spring事務。

  資料庫事務有嚴格的定義,必須同時滿足:原子性,一致性,隔離性,永續性。

原子性:表示組成一個事務的多條sql語句是一個不可分割的資料單元。所有語句執行成功才能提交,只要有一條語句執行失敗,所有操作必須全部撤銷。讓資料庫返回初始狀態。

一致性:事務操作成功後,資料次所處的狀態和這個資料庫業務規則是一致的,資料不會被破壞。假如在銀行系統中,兩個人相互轉賬,他們的總存款數應該不變,不能因為事務的執行發生變化。

隔離性:在併發操作時,各個事務擁有各自的操作空間,他們的操作不會對對方產生干擾。資料庫規定了不同的隔離級別,不同級別對應在併發操作資料庫時的不同干擾程度。隔離級別越高,資料一致性越好,但是併發性越弱。

永續性:一旦事務執行成功。就會被持久化到資料庫。

其中“一致性”是最終目標。其他三個特性都是為了達到這一目標所確定的。

資料併發問題:

髒讀:B事務執行時發生了錯誤回滾。但是A恰巧讀到了B回滾之前的資料,並執行成功。這樣A的資料應該是錯誤的,不被承認的。

不可重複讀:A讀取了兩次資料,但在這兩次讀取之間B更改了該資料。這樣A兩次讀取到的資料就會不一樣。

幻象讀:A讀取了兩次符合條件的資料,但在這兩次讀取之間B新增加了資料。這樣A兩次讀取到的資料就會不一致

不可重複讀和幻象讀的區別就是,不可重複讀是讀取更改的滿足條件資料,幻象讀是讀取到新增加的滿足條件的新資料。解決前者要為資料新增行級鎖,後者要新增表級鎖。

第一類丟失更新:A在回滾時覆蓋了B提交的事務。假如B事務讓銀行新進賬100,A回滾後B的操作也被覆蓋掉。銀行賠了100。

第二類丟失更新:A在提交事務時,把B提交的事務覆蓋了。假如事務A讀取銀行存款1000並新增100,這時B也做同樣操作,但是A提交後把B提交結果覆蓋掉了,銀行又賠了100。

資料庫通過鎖來解決併發訪問的問題,insert,update,delete,select for update 都會隱式採用必要的行級鎖。

事務隔離級別。資料庫為了方便使用者操作設定了4個隔離級別。使用者只需要設定相應的隔離級別,事務操作就會為資料資源新增合適的鎖。

ANSI/ISO SQL 92定義了4個隔離級別。

Read uncommitted :不允許第一類丟失更新

Read commited:不允許髒讀和第一類丟失更新

Repetable read :只允許幻象讀

Serializable :全都不允許

mysql資料庫預設repetable read 隔離級別。它只允許幻象讀。

Spring為了方便管理巢狀事務,定義了7中傳播行為

PROPAGATION_REQUIRED:如果當前沒有事務就新建一個事務,有就加入到這個事務中執行。

PROPAGATOIN_SUPPORTS:當前有事務就在當前事務中執行,沒有就以非事務執行。

PROPAGATION_MANDATORY:當前有事務就在當前事務中執行,沒有就丟擲異常。

PROPAGATION_REQUIRES_NEW:新建立一個事務執行,如果當前有事務執行,就把當前事務掛起。

PROPAGATION_NOT_SUPPORT:以非事務方式執行,如果當前有事務就把其掛起。

PROPAGATION_NEVER:不支援事務,如果當前存在事務,就丟擲異常。

PROPAGATION_NESTED:如果當前有事務,就巢狀在事務中執行。沒有就新建一個事務執行。

以上是spring 3.x企業應用開發實戰裡的內容

我用的註解得方式執行事務操作,別忘了在配置檔案裡定義事務管理器。

事務複習完了,繼續說刪除方法的執行過程,由於從表的多條記錄對應主表的一條記錄。而我又不想,多次與資料庫互動刪除。就想到的批量操作,我想到了in關鍵字,但是in關鍵字在大資料量的時候效率不高,它會導致全表掃描。

又找到了一條sql這樣寫  delete from xx using(values (1),(2),(3)) as tmp(id) where xx.id = tmp.id

說一下:VALUES關鍵字是根據給定的值表示式計算一個或一組行的值。它通常用於在一個較大的命令內生成一個"常數表",當同時它也可以用於自身。

using 後面跟一個表示式列表,允許來自其他表的列出現在 WHERE 條件中。這與可以在 SELECT 命令的 FROM 子句 中指定的表列表相似。例如,可以為該表的名字宣告一個別名。不要在 usinglist 裡重複目標表,除非你希望產生一個自連線。

由於需要把很多主鍵值放到values旁邊的多個括號裡,所以又要用到mybatis的動態sql了。

動態sql我不太熟悉。下回再寫關於動態sql的。這裡就先用到的foreach標籤。裡面有幾個屬性 collection是要遍歷的集合型別,可不是要傳入的集合名哦。 item是每次遍歷到的值。Index對於list來說是遍歷元素的序號,對於set來說是key值。Separator是拼出來每個元素間的分隔符。Open是foraeach拼出的串的最開始符號可以是左括號,close是結束符號。他倆配合使用。下面是批量刪除加上動態sql語句:

delete from twatch_enterprise  a
using (values
<foreach item="item" index="index" collection="list" separator=",">
  (#{item})
</foreach>
) as mid(id) where a.leased = mid.id

把sql語句都放進一個dubbo service方法裡,再在方法上面新增Transcational註解,屬性是

propagaton = PROPAGATION.REQUIRED ,isolation=repetable read,rollbackfor = {SQLExcation.class}。

就ok了。