最詳細的@Transactional講解


spring如何處理事務呢?下面是個偽代碼示意:

	  begin Transactional;
       try{
           //TODO
           commit;
       }catch (Throwable e){
           if(e屬於該提交的(即noRollbackFor指定)的異常類型){
               commit;
           }else {
               rollback;
           }
       }

1. transactionManager 當在配置文件中有多個TransactionManager,可以用該屬性指定使用哪個事務管理器

如果要配置全局事務管理,參考這篇文章全局性事務控制如何在springboot中配置

2. propagation 事務的傳播行為 ,默認值為REQUIRED

  • Propagation.REQUIRED
    默認傳播行為 如果有事務那么加入此事務,沒有就新建一個事務
	/**
	 * Support a current transaction, create a new one if none exists.
	 * <p>This is the default setting of a transaction annotation.
	 */
  • Propagation.SUPPORTS
    如果其他bean調用這個方法,在其他bean中聲明了事務那么久加入事務,如果其他bean中沒有聲明事務就不用事務
	/**
	 * Support a current transaction, execute non-transactionally if none exists.
	 * <p>Note: For transaction managers with transaction synchronization,
	 * PROPAGATION_SUPPORTS is slightly different from no transaction at all,
	 * as it defines a transaction scope that synchronization will apply for.
	 * As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
	 * will be shared for the entire specified scope. Note that this depends on
	 * the actual synchronization configuration of the transaction manager.
	 */
  • Propagation.REQUIRES_NEW
    不管是否存在事務,都創建一個新的事務。如果已經存在一個事務就停止他
	/**
	 * Create a new transaction, suspending the current transaction if one exists.
	 * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
	 * on all transaction managers. This in particular applies to
	 * {@link org.springframework.transaction.jta.JtaTransactionManager},
	 * which requires the {@code javax.transaction.TransactionManager} to be
	 * made available it to it (which is server-specific in standard Java EE).
	 * <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own
	 * transaction synchronizations. Existing synchronizations will be suspended
	 * and resumed appropriately.
	 */
  • Propagation.NOT_SUPPORTED
    不為這個方法開啟事務
	/**
	 * Do not support a current transaction; rather always execute non-transactionally.
	 * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
	 * on all transaction managers. This in particular applies to
	 * {@link org.springframework.transaction.jta.JtaTransactionManager},
	 * which requires the {@code javax.transaction.TransactionManager} to be
	 * made available it to it (which is server-specific in standard Java EE).
	 * <p>Note that transaction synchronization is <i>not</i> available within a
	 * {@code PROPAGATION_NOT_SUPPORTED} scope. Existing synchronizations
	 * will be suspended and resumed appropriately.
	 */
  • Propagation.MANDATORY
    必須當前存在事務,否則拋出異常
	/**
	 * Support a current transaction, throw an exception if none exists.
	 * Analogous to EJB transaction attribute of the same name.
	 */
  • Propagation.NEVER
    必須當前沒有事務,否則拋出異常,與Propagation.MANDATORY相反
	/**
	 * Execute non-transactionally, throw an exception if a transaction exists.
	 */
  • Propagation.NESTED
    如果當前存在事務,則在嵌套事務中執行,類似於ROPAGATION_REQUIRED
	/**
	 * Execute within a nested transaction if a current transaction exists,
	 * behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB.
	 * <p>Note: Actual creation of a nested transaction will only work on specific
	 * transaction managers. Out of the box, this only applies to the JDBC
	 */

嵌套事務中發生異常會回滾到savePoint,不對主事務之前的操作產生影響,但提交還要依賴主事務的成功。
在這里插入圖片描述

3. isolation 事務的隔離度 默認值為DEFAULT

  • DEFAULT使用數據庫默認的級別
    postgres數據庫的默認隔離級別是已提交讀 ,MySQL的默認事務隔離級別是可重復讀。
  • READ_UNCOMMITTED 未提交讀
	 A constant indicating that dirty reads, non-repeatable reads and phantom reads
	 * can occur. This level allows a row changed by one transaction to be read by
	 * another transaction before any changes in that row have been committed
	 * (a "dirty read"). If any of the changes are rolled back, the second
	 * transaction will have retrieved an invalid row.
  • READ_COMMITTED 已提交讀
	 A constant indicating that dirty reads are prevented; non-repeatable reads
	 * and phantom reads can occur. This level only prohibits a transaction
	 * from reading a row with uncommitted changes in it.
  • REPEATABLE_READ 可重復讀
		A constant indicating that dirty reads and non-repeatable reads are
	 * prevented; phantom reads can occur. This level prohibits a transaction
	 * from reading a row with uncommitted changes in it, and it also prohibits
	 * the situation where one transaction reads a row, a second transaction
	 * alters the row, and the first transaction rereads the row, getting
	 * different values the second time (a "non-repeatable read").
  • SERIALIZABLE 串行化
     A constant indicating that dirty reads, non-repeatable reads and phantom
	 * reads are prevented. This level includes the prohibitions in
	 * {@code ISOLATION_REPEATABLE_READ} and further prohibits the situation
	 * where one transaction reads all rows that satisfy a {@code WHERE}
	 * condition, a second transaction inserts a row that satisfies that
	 * {@code WHERE} condition, and the first transaction rereads for the
	 * same condition, retrieving the additional "phantom" row in the second read.

幻讀和不可重復讀相似容易混淆,幻讀值得是相同查詢條件的查詢行數,另一個事務增加或刪除了某行,導致第一個事務兩次查詢的行數不同。不可重復讀指的是另一個事物修改了某行的數據。

隔離和鎖是不同的東西,隔離不是靠鎖實現,是根據對數據的監控實現的,相比鎖會回滾事務。

4. timeout 事務的超時時間 默認值為-1. 超時自動回滾

如果事務超過時間限制還沒完成,就會回滾。
從方法執行開始計算。每個sql執行前檢查一次是否超時,方法全部執行完畢后不檢查是否超時。即設置事務超時為10秒,即使整個方法耗時20秒也不一定超時。

假設事務超時時間設置為2秒;假設sql執行時間為1秒;
如下調用是事務不超時的

public void testTimeout() throws InterruptedException {  
    System.out.println(System.currentTimeMillis());  
    JdbcTemplate jdbcTemplate = new JdbcTemplate(ds);  
    jdbcTemplate.execute(" update test set hobby = hobby || '1'");  
    System.out.println(System.currentTimeMillis());  
    Thread.sleep(3000L);  
}  

而如下事務超時是起作用的:

public void testTimeout() throws InterruptedException {  
    Thread.sleep(3000L);  
    System.out.println(System.currentTimeMillis());  
    JdbcTemplate jdbcTemplate = new JdbcTemplate(ds);  
    jdbcTemplate.execute(" update test set hobby = hobby || '1'");  
    System.out.println(System.currentTimeMillis());  
}  

參考博客

5. readOnly 是否為只讀事務,默認值為false,即非只讀事務

 注意 在只讀事務中修改數據庫是會報錯的!

6. rollbackFor 指定能夠觸發事務回滾的異常類型 noRollbackFor 指定那些異常類型不回滾事務


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM