一、之前對事物的瞭解只是停留在聲明式事物,配置xml,或使用註解,事物的傳播行爲也只用過REQUIRED和SUPPORTS,能夠說對事物的瞭解很模糊。java
二、直到在開發中遇到問題。。spring
問題的描述是:編程
年末跑定時任務,獲取用戶年末過時積分,併發送積分即將過時的消息提示;緩存
過時積分作記錄,並與積分作關聯記錄,涉及兩表的操做;springboot
數據量較多,循環保存,要作到每次循環都會手動提交,而不是作緩存最後提交;併發
事物的傳播行爲爲默認的REQUIRED,二兩個表操做涉及到了嵌套事物;ide
So。。。優化
解決辦法:spa
1聲明式事物方式.net
@Transactional(propagation = Propagation.REQUIRES_NEW)
2採用了編程式事物
事物的傳播行爲選擇爲:PROPAGATION_REQUIRES_NEW
public boolean updateExpireCredit(Credit credit) throws Exception { // 事務開始-方法級別 DefaultTransactionDefinition def = new DefaultTransactionDefinition(); // 傳播行爲: 新建事務,若是當前存在事務,把當前事務掛起 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); def.setTimeout(30); // 事務狀態 TransactionStatus status = tm.getTransaction(def); boolean falg = false; try { creditRepository.save(credit); tm.commit(status); falg = true; } catch (Exception e) { e.printStackTrace(); log.error("出現異常,事務回滾:{}", e); if (!status.isCompleted()) { tm.rollback(status); } throw e; } return falg; }
PlatformTransactionManager
jdbc——org.springframework.jdbc.datasource.DataSourceTransactionManager
hibernate——HibernateTransactionManager
jpa——org.springframework.orm.jpa.JpaTransactionManager
java的jta——org.springframework.transaction.jta.JtaTransactionManager
TransactionDefinition接口內容以下:
public interface TransactionDefinition { int getPropagationBehavior(); // 返回事務的傳播行爲 int getIsolationLevel(); // 返回事務的隔離級別,事務管理器根據它來控制另一個事務能夠看到本事務內的哪些數據 int getTimeout(); // 返回事務必須在多少秒內完成 boolean isReadOnly(); // 事務是否只讀,事務管理器可以根據這個返回值進行優化,確保事務是隻讀的 }
注:PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區別在於, PROPAGATION_REQUIRES_NEW 徹底是一個新的事務, 而 PROPAGATION_NESTED 則是外部事務的子事務, 若是外部事務 commit, 嵌套事務也會被 commit, 這個規則一樣適用於 roll back.
在同一個應用程序或者不一樣應用程序中的多個事務在同一個數據集上併發執行時,可能會出現許多意外的問題。
併發事務所致使的問題能夠分爲如下三類:
① 髒讀:髒讀發生在一個事務讀取了另外一個事務改寫但尚未提交的數據時。若是改寫在稍後被回滾了,那麼第一個事務獲取的數據就是無效的。
② 不可重複讀:不可重複讀發生在一個事務執行相同的查詢兩次或兩次以上,可是每次都獲得不一樣的數據時。這一般是由於另外一個併發事務在兩次查詢期間更新了數據
③ 幻讀:幻讀與不可重複讀相似。它發生在一個事務(T1)讀取了幾行數據,接着另外一個併發事務(T2)插入了一些數據時。在隨後的查詢中,第一個事務(T1)就會發現多了一些本來不存在的記錄
注:
不可重複讀的重點是修改
幻讀的重點在於新增或者刪除
PlatformTransactionManager接口的getTransaction()的方法獲得的是TransactionStatus接口的一個實現,這個接口的內容以下:
public interface TransactionStatus{ boolean isNewTransaction(); // 是不是新的事物 boolean hasSavepoint(); // 是否有恢復點 void setRollbackOnly(); // 設置爲只回滾 boolean isRollbackOnly(); // 是否爲只回滾 boolean isCompleted; // 是否已完成 }
6.編程時事物和聲明式事物