1. 程式人生 > >通過TransactionDefinition介面來學習spring事務的隔離級別和傳播特性(4.3.4版本)

通過TransactionDefinition介面來學習spring事務的隔離級別和傳播特性(4.3.4版本)

通過spring官方包中帶的原始碼來看spring的事務的5中隔離級別和7種傳播特性;    

原始碼如下:

/*
 * Copyright 2002-2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
* * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/ package org.springframework.transaction; import java.sql.Connection; /** * Interface that defines Spring-compliant transaction properties. * Based on the propagation behavior definitions analogous to EJB CMT attributes. * * <p>Note that isolation level and timeout settings will not get applied unless
* an actual new transaction gets started. As only {@link #PROPAGATION_REQUIRED}, * {@link #PROPAGATION_REQUIRES_NEW} and {@link #PROPAGATION_NESTED} can cause * that, it usually doesn't make sense to specify those settings in other cases. * Furthermore, be aware that not all transaction managers will support those * advanced features and thus might throw corresponding exceptions when given * non-default values. * * <p>The {@link #isReadOnly() read-only flag} applies to any transaction context, * whether backed by an actual resource transaction or operating non-transactionally * at the resource level. In the latter case, the flag will only apply to managed * resources within the application, such as a Hibernate {@code Session}. * * @author Juergen Hoeller * @since 08.05.2003 * @see PlatformTransactionManager#getTransaction(TransactionDefinition) * @see org.springframework.transaction.support.DefaultTransactionDefinition * @see org.springframework.transaction.interceptor.TransactionAttribute */ public interface TransactionDefinition { /** * Support a current transaction; create a new one if none exists. * Analogous to the EJB transaction attribute of the same name. * <p>This is typically the default setting of a transaction definition, * and typically defines a transaction synchronization scope. */ int PROPAGATION_REQUIRED = 0; //事務傳播級別1:當前如果有事務,Spring就會使用該事務;否則會開始一個新事務;(這也是預設設定和定義) /** * Support a current transaction; execute non-transactionally if none exists. * Analogous to the EJB transaction attribute of the same name. * <p><b>NOTE:</b> For transaction managers with transaction synchronization, * {@code PROPAGATION_SUPPORTS} is slightly different from no transaction * at all, as it defines a transaction scope that synchronization might apply to. * As a consequence, the same resources (a JDBC {@code Connection}, a * Hibernate {@code Session}, etc) will be shared for the entire specified * scope. Note that the exact behavior depends on the actual synchronization * configuration of the transaction manager! * <p>In general, use {@code PROPAGATION_SUPPORTS} with care! In particular, do * not rely on {@code PROPAGATION_REQUIRED} or {@code PROPAGATION_REQUIRES_NEW} * <i>within</i> a {@code PROPAGATION_SUPPORTS} scope (which may lead to * synchronization conflicts at runtime). If such nesting is unavoidable, make sure * to configure your transaction manager appropriately (typically switching to * "synchronization on actual transaction"). * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION */ int PROPAGATION_SUPPORTS = 1;//事務傳播級別2:如果有事務,Spring就會使用該事務;否則不會開始一個新事務 /** * Support a current transaction; throw an exception if no current transaction * exists. Analogous to the EJB transaction attribute of the same name. * <p>Note that transaction synchronization within a {@code PROPAGATION_MANDATORY} * scope will always be driven by the surrounding transaction. */ int PROPAGATION_MANDATORY = 2; //事務傳播級別3:當前如果有事務,Spring就會使用該事務;否則會因為沒有事務而丟擲異常 /** * Create a new transaction, suspending the current transaction if one exists. * Analogous to the EJB transaction attribute of the same name. * <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. * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager */ int PROPAGATION_REQUIRES_NEW = 3;//事務傳播級別4:總是要開啟一個新事務。如果當前已經有事務,則將已有事務掛起 /** * Do not support a current transaction; rather always execute non-transactionally. * Analogous to the EJB transaction attribute of the same name. * <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. * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager */ int PROPAGATION_NOT_SUPPORTED = 4;//事務傳播級別5:程式碼總是在非事務環境下執行,如果當前有事務,則將已有事務掛起,再執行程式碼,之後恢復事務 /** * Do not support a current transaction; throw an exception if a current transaction * exists. Analogous to the EJB transaction attribute of the same name. * <p>Note that transaction synchronization is <i>not</i> available within a * {@code PROPAGATION_NEVER} scope. */ int PROPAGATION_NEVER = 5; //事務傳播級別6:絕對不允許程式碼在事務中執行。如果當前執行環境有事務存在,則直接丟擲異常,結束執行 /** * Execute within a nested transaction if a current transaction exists, * behave like {@link #PROPAGATION_REQUIRED} else. There is no analogous * feature in EJB. * <p><b>NOTE:</b> Actual creation of a nested transaction will only work on * specific transaction managers. Out of the box, this only applies to the JDBC * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager} * when working on a JDBC 3.0 driver. Some JTA providers might support * nested transactions as well. * @see org.springframework.jdbc.datasource.DataSourceTransactionManager */ int PROPAGATION_NESTED = 6;//事務傳播級別7:該級別支援巢狀事務執行。如果沒有父事務存在,那麼執行情況與PROPAGATION_REQUIRED一樣;典型的應用是批量資料入庫,開啟父事務對一批資料入庫,而對於每條入庫的資料
   都有一個子事務對應,那麼當所有的子事務成功,父事務提交,才算成功,否則,就都失敗。


   /**
    * Use the default isolation level of the underlying datastore.
    * All other levels correspond to the JDBC isolation levels.
    * @see java.sql.Connection
    */
int ISOLATION_DEFAULT = -1;
//事務隔離級別1:預設的隔離級別,同資料庫一樣的,如果不做特別設定,mysql預設的是可重複讀,而oracle預設的是讀提交

   /**
    * Indicates that dirty reads, non-repeatable reads and phantom reads
    * can occur.
    * <p>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.
    * @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
    */
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
//事務隔離級別2:讀未提交,即一個事務可以讀取另外一個事務中未提交的資料,即髒讀資料存在,效能最好,但是沒啥用。
   /**
    * Indicates that dirty reads are prevented; non-repeatable reads and
    * phantom reads can occur.
    * <p>This level only prohibits a transaction from reading a row
    * with uncommitted changes in it.
    * @see java.sql.Connection#TRANSACTION_READ_COMMITTED
    */
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
//事務隔離級別3:讀提交,即一個事務只能讀取到另一個事務提交後的資料,oracle資料庫預設隔離級別;存在不可重複讀問題,即交叉事務出現,A事務兩次讀取資料可能會讀到B事務提交的修改後的資料,即在同一個事務中讀到了不同的資料,也叫不可重複讀
/**
* Indicates that dirty reads and non-repeatable reads are prevented;
* phantom reads can occur.
* <p>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 re-reads the row,
* getting different values the second time (a "non-repeatable read").
* @see java.sql.Connection#TRANSACTION_REPEATABLE_READ    */
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
//事務隔離級別4:可重複讀,即一個事務只能讀取到在次事務之前提交的資料,而之後提交不能讀取到,不管對方的事務是否提交都讀取不到,mysql預設的隔離級別。此隔離級別有可能會遇到幻讀現象,但是mysql 基於innodb引擎實現的資料庫已經通過多版本控制解決了此問題,所以可以不考慮了。
/**
* Indicates that dirty reads, non-repeatable reads and phantom reads
* are prevented.
* <p>This level includes the prohibitions in {@link #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
* re-reads for the same condition, retrieving the additional "phantom" row
* in the second read.    * @see java.sql.Connection#TRANSACTION_SERIALIZABLE
*/
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;  
//事務隔離級別2:序列化讀,每次都是全表鎖,效能最差,安全性最高,一般場景不適用,也沒有這個必要。
在開發的過程中,用事務最多的方式是通過註解@Transaction來完成的,雖然大多數的業務場景都可以在這一個註解下完成即可。
但是為了適應某些特別的場景比方說只讀方法的優化等,通過對@Transaction來新增引數來完成我們想要的事務傳播特性和隔離級別,以及是否只對某些異常類做回滾,是否只讀方法等。
1)使用propagation 指定事務的傳播行為,即當前的事務方法被另外一個事務方法呼叫時如何使用事務。
      預設取值為REQUIRED,即使用呼叫方法的事務
     REQUIRES_NEW:使用自己的事務,呼叫的事務方法的事務被掛起。
     
 2)使用isolation 指定事務的隔離級別,最常用的取值為READ_COMMITTED
 3)預設情況下 Spring 的宣告式事務對所有的執行時異常進行回滾,也可以通過對應的屬性進行設定。通常情況下,預設值即可。
 4)使用readOnly 指定事務是否為只讀。 表示這個事務只讀取資料但不更新資料,這樣可以幫助資料庫引擎優化事務。若真的是一個只讀取資料庫值得方法,應設定readOnly=true
 5)使用timeOut 指定強制回滾之前事務可以佔用的時間。
@Transactional(propagation = Propagation.MANDATORY,isolation = Isolation.READ_COMMITTED,noRollbackFor = {特定的異常類物件},readOnly = true,timeout = 3)
其中timeout的單位為秒。多個異常類物件,用逗號分隔即可。